弹簧引导环境属性占位符解析及类型转换详解

  


  

  

前面写过一篇关于环境属性加载的源码分析和扩展,里面提到属性的占位符解析和类型转换是相对复杂的,这篇文章就是要分析和解读这两个复杂的问题。关于这两个问题,选用一个比较复杂的参数处理方法PropertySourcesPropertyResolver # getProperty,解析占位符的时候依赖到

        PropertySourcesPropertyResolver # getPropertyAsRawString:      getPropertyAsRawString保护字符串(字符串键){   返回getProperty(键,字符串。类,假);   }      保护& lt; T>T getProperty(字符串键,Class布尔resolveNestedPlaceholders targetValueType) {   如果这一点。propertySources !=null) {   (PropertySource<& # 63;比;propertySource: this.propertySources) {   如果(logger.isTraceEnabled ()) {   记录器。跟踪(“寻找关键的“+键+”PropertySource”+   propertySource.getName () +“”);   }   对象价值=https://www.yisu.com/zixun/propertySource.getProperty(关键);   如果(价值!=null) {   如果(resolveNestedPlaceholders & &值运算符字符串){//解析带有占位符的属性   值=resolveNestedPlaceholders((字符串)值);   }   logKeyFound (propertySource,关键值);//需要时转换属性的类型   返回convertValueIfNecessary(价值,targetValueType);   }   }   }   如果(logger.isDebugEnabled ()) {   logger.debug(“找不到关键的“+键+”任何属性源”);   }   返回null;   }      


  

  

属性占位符的解析方法是PropertySourcesPropertyResolver的父类AbstractPropertyResolver # resolveNestedPlaceholders:

        resolveNestedPlaceholders保护字符串(字符串值){   返回(这。ignoreUnresolvableNestedPlaceholders & # 63;   resolvePlaceholders(价值):resolveRequiredPlaceholders(值));   }      

ignoreUnresolvableNestedPlaceholders属性默认为假,可以通过AbstractEnvironment # setIgnoreUnresolvableNestedPlaceholders(布尔ignoreUnresolvableNestedPlaceholders)设置,当此属性被设置为真的,解析属性占位符失败的时候(并且没有为占位符配置默认值)不会抛出异常,返回属性原样字符串,否则会抛出IllegalArgumentException。我们这里只需要分析AbstractPropertyResolver # resolveRequiredPlaceholders:

     //AbstractPropertyResolver中的属性://ignoreUnresolvableNestedPlaceholders=true情况下创建的PropertyPlaceholderHelper实例   @Nullable   私人PropertyPlaceholderHelper nonStrictHelper;//ignoreUnresolvableNestedPlaceholders=false情况下创建的PropertyPlaceholderHelper实例   @Nullable   私人PropertyPlaceholderHelper strictHelper;//是否忽略无法处理的属性占位符,这里是假的,也就是遇到无法处理的属性占位符且没有默认值则抛出异常   私人布尔ignoreUnresolvableNestedPlaceholders=false;//属性占位符前缀,这里是“$ {”   私人字符串placeholderPrefix=SystemPropertyUtils.PLACEHOLDER_PREFIX;//属性占位符后缀,这里是“}”   私人字符串placeholderSuffix=SystemPropertyUtils.PLACEHOLDER_SUFFIX;//属性占位符解析失败的时候配置默认值的分隔符,这里是”:“   @Nullable   私人字符串valueSeparator=SystemPropertyUtils.VALUE_SEPARATOR;         resolveRequiredPlaceholders公共字符串(字符串文本)抛出IllegalArgumentException {   如果这一点。strictHelper==null) {   这一点。strictHelper=createPlaceholderHelper(假);   }   返回doResolvePlaceholders(文本、this.strictHelper);   }//创建一个新的PropertyPlaceholderHelper实例,这里ignoreUnresolvablePlaceholders为假   私人PropertyPlaceholderHelper createPlaceholderHelper(布尔ignoreUnresolvablePlaceholders) {   返回新PropertyPlaceholderHelper(这一点。placeholderPrefix,这。placeholderSuffix,这。valueSeparator ignoreUnresolvablePlaceholders);   }//这里最终的解析工作委托到PropertyPlaceholderHelper # replacePlaceholders完成   私人doResolvePlaceholders字符串(字符串文本、PropertyPlaceholderHelper助手){   返回的助手。replacePlaceholders(文本、::getPropertyAsRawString);   }      

最终只需要分析PropertyPlaceholderHelper # replacePlaceholders,这里需要重点注意:

  

注意到这里的第一个参数文本就是属性值的源字符串,例如我们需要处理的属性为myProperties: {server.port} - {spring.application.name},美元这里的文本就是{server.port} - {spring.application.name}美元。
  

  

replacePlaceholders方法的第二个参数placeholderResolver,这里比较巧妙,这里的方法引用::getPropertyAsRawString相当于下面的代码:

弹簧引导环境属性占位符解析及类型转换详解