前面写过一篇关于环境属性加载的源码分析和扩展,里面提到属性的占位符解析和类型转换是相对复杂的,这篇文章就是要分析和解读这两个复杂的问题。关于这两个问题,选用一个比较复杂的参数处理方法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相当于下面的代码: