一、测试类

  1. public class Main {
  2. public static void main(String[] args) {
  3. ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:app-${user}.xml");
  4. Person person = applicationContext.getBean(Person.class);
  5. System.out.println(person.getName());
  6. }
  7. }

同时添加jvm参数-Duser=test

二、app-test.xml文件

  1. <beans>
  2. <bean id="person" class="xml.Person">
  3. <property value="张三" name="name"></property>
  4. </bean>
  5. </beans>

三、源码跟踪

  1. public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
  2. this(new String[] {configLocation}, true, null);
  3. }

创建ClassPathXmlApplicationContext从xml位置加载Bean定义。

  1. public ClassPathXmlApplicationContext(
  2. String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
  3. throws BeansException {
  4. super(parent); // 初始化父类
  5. setConfigLocations(configLocations); // 设置xml文件位置
  6. if (refresh) {
  7. refresh(); // 刷新容器
  8. }
  9. }

从super(parent);进去

  1. public AbstractApplicationContext(@Nullable ApplicationContext parent) {
  2. this();
  3. setParent(parent);
  4. }
  5. @Override
  6. public void setParent(@Nullable ApplicationContext parent) {
  7. this.parent = parent;
  8. if (parent != null) {
  9. Environment parentEnvironment = parent.getEnvironment();
  10. if (parentEnvironment instanceof ConfigurableEnvironment) {
  11. getEnvironment().merge((ConfigurableEnvironment) parentEnvironment); // 与父类的Environment对象合并
  12. }
  13. }
  14. }
  15. public void setConfigLocations(@Nullable String... locations) {
  16. if (locations != null) {
  17. Assert.noNullElements(locations, "Config locations must not be null");
  18. this.configLocations = new String[locations.length];
  19. for (int i = 0; i < locations.length; i++) {
  20. this.configLocations[i] = resolvePath(locations[i]).trim(); // 解析xml文件的路径,xml文件路径可能存在${}的情况,需要解析替换
  21. }
  22. }
  23. else {
  24. this.configLocations = null;
  25. }
  26. }
  27. protected String resolvePath(String path) {
  28. return getEnvironment().resolveRequiredPlaceholders(path); // 解析${...}并替换
  29. }
  30. @Override
  31. public ConfigurableEnvironment getEnvironment() {
  32. if (this.environment == null) {
  33. this.environment = createEnvironment();
  34. }
  35. return this.environment;
  36. }
  37. protected ConfigurableEnvironment createEnvironment() {
  38. return new StandardEnvironment();
  39. }

查看StandardEnvironment的父类AbstractEnvironment构造函数

  1. public AbstractEnvironment() {
  2. this(new MutablePropertySources());
  3. }
  4. protected AbstractEnvironment(MutablePropertySources propertySources) {
  5. this.propertySources = propertySources;
  6. this.propertyResolver = createPropertyResolver(propertySources);
  7. customizePropertySources(propertySources);
  8. }
  9. protected void customizePropertySources(MutablePropertySources propertySources) {
  10. }

StandardEnvironment的customizePropertySources方法

  1. @Override
  2. protected void customizePropertySources(MutablePropertySources propertySources) {
  3. propertySources.addLast(
  4. new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
  5. propertySources.addLast(
  6. new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
  7. }

AbstractEnvironment类

  1. @Override
  2. @SuppressWarnings({"rawtypes", "unchecked"})
  3. public Map<String, Object> getSystemProperties() {
  4. try {
  5. return (Map) System.getProperties(); // 获取JVM属性
  6. }
  7. catch (AccessControlException ex) {
  8. return (Map) new ReadOnlySystemAttributesMap() {
  9. @Override
  10. @Nullable
  11. protected String getSystemAttribute(String attributeName) {
  12. try {
  13. return System.getProperty(attributeName);
  14. }
  15. catch (AccessControlException ex) {
  16. if (logger.isInfoEnabled()) {
  17. logger.info("Caught AccessControlException when accessing system property '" +
  18. attributeName + "'; its value will be returned [null]. Reason: " + ex.getMessage());
  19. }
  20. return null;
  21. }
  22. }
  23. };
  24. }
  25. }
  26. @Override
  27. @SuppressWarnings({"rawtypes", "unchecked"})
  28. public Map<String, Object> getSystemEnvironment() {
  29. if (suppressGetenvAccess()) {
  30. return Collections.emptyMap();
  31. }
  32. try {
  33. return (Map) System.getenv(); // 获取系统设置的属性
  34. }
  35. catch (AccessControlException ex) {
  36. return (Map) new ReadOnlySystemAttributesMap() {
  37. @Override
  38. @Nullable
  39. protected String getSystemAttribute(String attributeName) {
  40. try {
  41. return System.getenv(attributeName);
  42. }
  43. catch (AccessControlException ex) {
  44. if (logger.isInfoEnabled()) {
  45. logger.info("Caught AccessControlException when accessing system environment variable '" +
  46. attributeName + "'; its value will be returned [null]. Reason: " + ex.getMessage());
  47. }
  48. return null;
  49. }
  50. }
  51. };
  52. }
  53. }

resolveRequiredPlaceholders

  1. //AbstractEnvironment
  2. @Override
  3. public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
  4. return this.propertyResolver.resolveRequiredPlaceholders(text); \\ propertyResolverPropertySourcesPropertyResolver
  5. }

在创建StandardEnvironment对象时

  1. public AbstractEnvironment() {
  2. this(new MutablePropertySources());
  3. }
  4. protected AbstractEnvironment(MutablePropertySources propertySources) {
  5. this.propertySources = propertySources;
  6. this.propertyResolver = createPropertyResolver(propertySources);
  7. customizePropertySources(propertySources);
  8. }
  9. protected ConfigurablePropertyResolver createPropertyResolver(MutablePropertySources propertySources) {
  10. return new PropertySourcesPropertyResolver(propertySources);
  11. }

PropertySourcesPropertyResolver的父类AbstractPropertyResolver的方法resolveRequiredPlaceholders

  1. @Override
  2. public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
  3. if (this.strictHelper == null) {
  4. this.strictHelper = createPlaceholderHelper(false);
  5. }
  6. return doResolvePlaceholders(text, this.strictHelper);
  7. }
  8. private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {
  9. return helper.replacePlaceholders(text, this::getPropertyAsRawString);
  10. }
  11. public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) {
  12. Assert.notNull(value, "'value' must not be null");
  13. return parseStringValue(value, placeholderResolver, null);
  14. }
  15. protected String parseStringValue(
  16. String value, PlaceholderResolver placeholderResolver, @Nullable Set<String> visitedPlaceholders) {
  17. int startIndex = value.indexOf(this.placeholderPrefix); //placeholderPrefix = "${"; 查找前缀位置
  18. if (startIndex == -1) {
  19. return value;
  20. }
  21. StringBuilder result = new StringBuilder(value);
  22. while (startIndex != -1) {
  23. int endIndex = findPlaceholderEndIndex(result, startIndex); // 从startIndex开始在result查找placeholderSuffix的位置
  24. if (endIndex != -1) {
  25. String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
  26. String originalPlaceholder = placeholder;
  27. if (visitedPlaceholders == null) {
  28. visitedPlaceholders = new HashSet<>(4);
  29. }
  30. if (!visitedPlaceholders.add(originalPlaceholder)) {
  31. throw new IllegalArgumentException(
  32. "Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
  33. }
  34. // Recursive invocation, parsing placeholders contained in the placeholder key.
  35. placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders); //递归调用parseStringValue解析placeholder,${}里面可能存在${}
  36. // Now obtain the value for the fully resolved key...
  37. String propVal = placeholderResolver.resolvePlaceholder(placeholder); //通过系统属性解析placeholder
  38. if (propVal == null && this.valueSeparator != null) { // 设置默认值
  39. int separatorIndex = placeholder.indexOf(this.valueSeparator);
  40. if (separatorIndex != -1) {
  41. String actualPlaceholder = placeholder.substring(0, separatorIndex);
  42. String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
  43. propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
  44. if (propVal == null) {
  45. propVal = defaultValue;
  46. }
  47. }
  48. }
  49. if (propVal != null) {
  50. // Recursive invocation, parsing placeholders contained in the
  51. // previously resolved placeholder value.
  52. propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
  53. result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
  54. if (logger.isTraceEnabled()) {
  55. logger.trace("Resolved placeholder '" + placeholder + "'");
  56. }
  57. startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());
  58. }
  59. else if (this.ignoreUnresolvablePlaceholders) {
  60. // Proceed with unprocessed value.
  61. startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
  62. }
  63. else {
  64. throw new IllegalArgumentException("Could not resolve placeholder '" +
  65. placeholder + "'" + " in value \"" + value + "\"");
  66. }
  67. visitedPlaceholders.remove(originalPlaceholder);
  68. }
  69. else {
  70. startIndex = -1;
  71. }
  72. }
  73. return result.toString();
  74. }
  75. private int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
  76. int index = startIndex + this.placeholderPrefix.length();
  77. int withinNestedPlaceholder = 0;
  78. while (index < buf.length()) {
  79. if (StringUtils.substringMatch(buf, index, this.placeholderSuffix)) { // placeholderSuffix = "}"
  80. if (withinNestedPlaceholder > 0) {
  81. withinNestedPlaceholder--;
  82. index = index + this.placeholderSuffix.length();
  83. }
  84. else {
  85. return index;
  86. }
  87. }
  88. else if (StringUtils.substringMatch(buf, index, this.simplePrefix)) {
  89. withinNestedPlaceholder++;
  90. index = index + this.simplePrefix.length();
  91. }
  92. else {
  93. index++;
  94. }
  95. }
  96. return -1;
  97. }

Spring源码-入门的更多相关文章

  1. Spring源码入门——DefaultBeanNameGenerator解析 转发 https://www.cnblogs.com/jason0529/p/5272265.html

    Spring源码入门——DefaultBeanNameGenerator解析   我们知道在spring中每个bean都要有一个id或者name标示每个唯一的bean,在xml中定义一个bean可以指 ...

  2. Spring源码入门——DefaultBeanNameGenerator解析

    我们知道在spring中每个bean都要有一个id或者name标示每个唯一的bean,在xml中定义一个bean可以指定其id和name值,但那些没有指定的,或者注解的spring的beanname怎 ...

  3. Spring源码入门——XmlBeanDefinitionReader解析

    接上篇[] ,我们看到BeanDefinitionReader解决的是从资源文件(xml,propert)到BeanDefinition集合的过程.所以BeanDefinitionReader接口有两 ...

  4. Spring源码入门——AnnotationBeanNameGenerator解析

    ---恢复内容开始--- 接上篇,上篇解析了DefaultBeanGenerator生成bean name的过程(http://www.cnblogs.com/jason0529/p/5272265. ...

  5. 从零开始学spring源码之xml解析(一):入门

    谈到spring,首先想到的肯定是ioc,DI依赖注入,aop,但是其实很多人只是知道这些是spring核心概念,甚至不知道这些代表了什么意思,,作为一个java程序员,怎么能说自己对号称改变了jav ...

  6. spring源码:学习线索(li)

    一.spring xml配置(不包括AOP,主要了解在初始化及实例化过程中spring配置文件中每项内容的具体实现过程,从根本上掌握spring) <bean>的名字 &,alia ...

  7. 阅读spring源码

    读Spring源码之前,你要先清楚,为什么你要用Spring... Spring最基本的功能是做为管理bean的容器,所以我以为应该先从org.springframework.context包了解咯, ...

  8. spring源码:学习线索

    一.spring xml配置(不包括AOP,主要了解在初始化及实例化过程中spring配置文件中每项内容的具体实现过程,从根本上掌握spring) <bean>的名字 &,alia ...

  9. spring 源码解析

    1. [文件] spring源码.txt ~ 15B     下载(167) ? 1 springн┤┬вио╬Ш: 2. [文件] spring源码分析之AOP.txt ~ 15KB     下载( ...

随机推荐

  1. JAVA - 缓冲和缓存

    JAVA - 缓冲和缓存 缓冲 Buffer 功能:协调上下层应用之间的性能差异.通过缓冲区的缓冲,当上层组件性能优于下层组件的时候,缓冲可以有效减少上层组件对下层组件的等待时间. 使用场景:IO流中 ...

  2. SpringCloud 配置管理:Nacos

    目录 统一配置管理 配置热更新 配置共享 多环境配置共享 多服务配置共享 统一配置管理 将配置交给 Nacos 管理的步骤: 在 Nacos 中添加配置文件. 在微服务中引入 nacos 的 conf ...

  3. CabloyJS究竟是一款什么样的框架

    CabloyJS是什么样的框架 CabloyJS 是一款自带工作流引擎的 Node.js 全栈框架,一款面向开发者的低代码开发平台,更是一款兼具低代码的开箱即用和专业代码的灵活定制的 PAAS 平台 ...

  4. GDOI 2021 普及组溺水记

    Day 1 T1 一看样例:答案不就是 \(\dfrac{\max_{i=1}^n a_i +1}{2}\) 吗? 于是自信打上,拍都不拍.然后就,,对了? 插曲:自己出了一个极端数据,发现 scan ...

  5. C语言学习之我见-strncpy()字符串复制函数(可控制范围)

    strncpy()函数,用于两个字符串值的复制. (1)函数原型 char *strncpy(char * _Dest,const char * _Source,size_t _Count); (2) ...

  6. numpy学习笔记02

    简介 numpy.array() 数组对象,可以表示普通的一维数组,或者二维矩阵,或者任意数据:并且它可以对数组中的数据进行非常高效的运算,如:数据统计.图像处理.线性代数等 numpy 之所以能运行 ...

  7. Vue.js CLI4 Vue.config.js标准配置 (最全注释)

    前言: Vue.js CLI工具 不知不觉发展到了4.0时代,CLI给人最直白的感受是没有了build文件夹跟config文件夹,所有的配置都在Vue.config.js完成.那么该文件的配置至关重要 ...

  8. 关于Vue Element组件el-checkbox与el-select默认选中值的几点注意事项

    el-select 示例: 代码: <el-select v-model="doc.zhic" placeholder="请选择"> <el- ...

  9. C++ 炼气期之数组探幽

    1. 数组概念 变量是内存中的一个存储块,大小由声明时的数据类型决定. 数组可以认为是变量的集合,在内存中表现为一片连续的存储区域,其特点为: 同类型多个变量的集合. 每一个变量没有自己的名字. 数组 ...

  10. RPA工单查询和下载流程机器人

    1.登录业务系统,输入用户名和密码 2.进入下载模块 3.输入下载查询条件 4.进入文件明细单 5.下载文件 视频地址:https://www.bilibili.com/video/BV1964y1D ...