Spring ClassPathXmlApplicationContext setConfigLocations方法

42 阅读1分钟

image.png image.png

image.png

getEnvironment方法

image.png

createEnvironment()当中调用new StandardEnvironment()。
StandardEnvironment调用父类AbstractEnvironment构造方法,
AbstractEnvironment构造方法调用子类(StandardEnvironment)的customizePropertySources(this.propertySources);

image.png

image.png customizePropertySources方法添加环境属性、系统变量 image.png

image.png

image.png

resolveRequiredPlaceholders方法

image.png getEnvironment().resolveRequiredPlaceholders(path)​调用到AbstractEnvironment的resolveRequiredPlaceholders方法 image.png propertySources 就是 createEnvironment方法时 new StandardEnvironment() 上面调用customizePropertySources时往里面添加系统变量和环境变量 image.png

PropertySourcesPropertyResolver调用父类AbstractPropertyResolver的resolveRequiredPlaceholders方法 image.png createPlaceholderHelper方法创建赋值给this.strictHelper image.png

PropertyPlaceholderHelper

image.png image.png doResolvePlaceholders方法将配置文件中的占位符进行值的替换处理

image.png

image.png

PropertyPlaceholderHelper#replacePlaceholders

在上面,PlaceholderResolver placeholderResolver 入参是一个lambda表达式,具体实现在PlaceholderResolver的子类PropertySourcesPropertyResolver的getPropertyAsRawString方法

image.png

public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) {
   Assert.notNull(value, "'value' must not be null");
   return parseStringValue(value, placeholderResolver, null);
}

/**
 * 解析字符串中的占位符(例如 ${...})
 * 
 * @param value                待解析的原始字符串
 * @param placeholderResolver  占位符解析器(用于查找占位符对应的实际值)
 * @param visitedPlaceholders  已访问的占位符集合(用于检测循环引用,可为 null)
 * @return 解析后的字符串
 */
protected String parseStringValue(
      String value, PlaceholderResolver placeholderResolver, @Nullable Set<String> visitedPlaceholders) {

   int startIndex = value.indexOf(this.placeholderPrefix);
   if (startIndex == -1) {
      return value;
   }

   StringBuilder result = new StringBuilder(value);
   while (startIndex != -1) {
      int endIndex = findPlaceholderEndIndex(result, startIndex);
      if (endIndex != -1) {
         // 从${username} 解析出 username
         String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
         String originalPlaceholder = placeholder;
         if (visitedPlaceholders == null) {
            visitedPlaceholders = new HashSet<>(4);
         }
         // 检测循环引用(如 ${a} 引用 ${b},${b} 又引用 ${a})
         if (!visitedPlaceholders.add(originalPlaceholder)) {
            throw new IllegalArgumentException(
                  "Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
         }
         // Recursive invocation, parsing placeholders contained in the placeholder key.
         placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
         // Now obtain the value for the fully resolved key...
         // placeholderResolver: 即入参 this::getPropertyAsRawString, 调用PropertySourcesPropertyResolver.getPropertyAsRawString()
         // 通过解析器获取占位符的实际值
         String propVal = placeholderResolver.resolvePlaceholder(placeholder);
         if (propVal == null && this.valueSeparator != null) {
            int separatorIndex = placeholder.indexOf(this.valueSeparator);
            if (separatorIndex != -1) {
               String actualPlaceholder = placeholder.substring(0, separatorIndex);
               String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
               propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
               if (propVal == null) {
                  propVal = defaultValue;
               }
            }
         }
         if (propVal != null) {
            // Recursive invocation, parsing placeholders contained in the
            // previously resolved placeholder value.
            // 递归解析占位符 KEY 本身可能嵌套的占位符(例如解析 ${${inner}})
            propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
            result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
            if (logger.isTraceEnabled()) {
               logger.trace("Resolved placeholder '" + placeholder + "'");
            }
            startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());
         }
         // 未开启 ignoreUnresolvablePlaceholders 时,遇到无法解析的占位符立即抛异常
         else if (this.ignoreUnresolvablePlaceholders) {
            // Proceed with unprocessed value.
            startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
         }
         else {
            throw new IllegalArgumentException("Could not resolve placeholder '" +
                  placeholder + "'" + " in value "" + value + """);
         }
         visitedPlaceholders.remove(originalPlaceholder);
      }
      else {
         startIndex = -1;
      }
   }
   return result.toString();
}

image.png

image.png

public class Test1 {

    public static void main(String[] args) {
        Properties properties = new Properties();
        properties.put("msg", "this is msg");
        properties.put("userJueJin.msg", "msg:${msg}");

        // 模仿AbstractEnvironment
        MutablePropertySources propertySources = new MutablePropertySources();
        ConfigurablePropertyResolver propertyResolver = new PropertySourcesPropertyResolver(propertySources);
        // 模仿StandardEnvironment
        propertySources.addLast(new PropertiesPropertySource("test", properties));
        // 简单取值
        String msg = propertyResolver.getProperty("msg");
        // 占位符解析
        String result = propertyResolver.resolveRequiredPlaceholders("userJueJin.msg");
    }
}