@ConfigurationProperties 的属性注入是在 initializeBean() 的时候处理的,即 populateBean() 之后,由 ConfigurationPropertiesBindingPostProcessor 处理的,最终会委托给 Environment 来处理(参看:SpringBoot 配置项解析)。
而 @Value 的属性注入是在 populateBean() 的时候处理的,是当作依赖进行注入的。最后是通过 AbstractBeanFactory.embeddedValueResolvers (一组 StringValueResoulver 的集合) 解析的,它非常强大,支持 占位符 ${} 和 spEL(#{})
org.springframework.beans.factory.support.AbstractBeanFactory#resolveEmbeddedValue()
public String resolveEmbeddedValue(@Nullable String value) { if (value == null) { return null; } String result = value; for (StringValueResolver resolver : this.embeddedValueResolvers) { result = resolver.resolveStringValue(result); if (result == null) { return null; } } return result; }
StringValueResolver、EmbeddedValueResolver
EmbeddedValueResolver implements StringValueResolver。EmbeddedValueResolver 非常强大,它是 spring 配置解析的核心。先解析占位符 ${},再解析 spEL(#{})
1 public class EmbeddedValueResolver implements StringValueResolver { 2 private final BeanExpressionContext exprContext; 3 private final BeanExpressionResolver exprResolver; 4 5 public EmbeddedValueResolver(ConfigurableBeanFactory beanFactory) { 6 this.exprContext = new BeanExpressionContext(beanFactory, null); 7 this.exprResolver = beanFactory.getBeanExpressionResolver(); // 实现类为:StandardBeanExpressionResolver 8 } 9 10 @Override 11 public String resolveStringValue(String strVal) { 12 // 1. 解析占位符${} 13 String value = this.exprContext.getBeanFactory().resolveEmbeddedValue(strVal); 14 if (this.exprResolver != null && value != null) { 15 // 2. 解析 spEL: #{} 16 Object evaluated = this.exprResolver.evaluate(value, this.exprContext); 17 value = (evaluated != null ? evaluated.toString() : null); 18 } 19 return value; 20 } 21 22 }
配置写法小技巧:
可以使用嵌套写法 和 默认值。举例:
${server.error.path:${error.path:/error}}
问题思考:
用了 disconf 之后,在使用 SpringBoot @ConfigurationProperties 形式的配置时,是不是就不用写 @PropertySource("classpath:redis.properties") 来指定配置文件了?因为 diconf 已经将托管的 property 配置文件纳入 spring 管理了,如果这样该多方便啊。那确实可以这么干吗?
(在使用 disconf 托管配置文件时,会配置 org.springframework.context.support.PropertySourcesPlaceholderConfigurer 或者 com.baidu.disconf.client.addons.properties.ReloadingPropertyPlaceholderConfigurer,被托管的配置都会纳入 spring 管理。)
分析:
通过测试发现是不可以的,因为 @ConfigurationProperties 最终委托给 Environment 来处理,而 PropertySourcesPlaceholderConfigurer 和 ReloadingPropertyPlaceholderConfigurer 都不受 Environment 控制,所以是不支持的。
而 @Value 却是可以注入 disconf 托管的配置的,因为 @Value 注入的配置会通过 StringValueResoulver 来解析,而 PropertySourcesPlaceholderConfigurer 和 ReloadingPropertyPlaceholderConfigurer 管理的配置,最终会间接通过 StringValueResolver 来解析
资料:
https://blog.csdn.net/f641385712/article/details/91380598