扩展配置的注解。如果要绑定和验证某些配置属性(例如,来自.properties文件),则将其添加到@Configuration 或@Bean 定义的类中。
注意,与@value不同,不会计算Spel表达式,因为属性值是扩展的。
@ConfigurationProperties 使用场景
作为某个配置集合,以对象的形式提供配置,更加符合面向对象的思想。
原有采用@Value配置属性的场景,如果是相关的多个配置项,可以采用对象的形式提供。
@ConfigurationProperties 处理过程
关键类:EnableConfigurationProperties、EnableConfigurationPropertiesImportSelector
- EnableConfigurationProperties 作用:注册@ConfigurationProperties的类作为bean
- EnableConfigurationPropertiesImportSelector 作用:引入ConfigurationPropertiesBeanRegistrar、ConfigurationPropertiesBindingPostProcessorRegistrar
- ConfigurationPropertiesBeanRegistrar作用:将注解的类注册为Bean
- ConfigurationPropertiesBindingPostProcessorRegistrar作用:引入ConfigurationPropertiesBindingPostProcessor,实例化配置类并注入配置值
ConfigurationProperties 配置类实例化过程
核心类:PropertiesConfigurationFactory
核心方法:doBindPropertiesToTarget,绑定配置项到配置类属性并提供校验。
private void doBindPropertiesToTarget() throws BindException {
RelaxedDataBinder dataBinder = (this.targetName != null ? new RelaxedDataBinder(this.target, this.targetName) : new RelaxedDataBinder(this.target));
// 一如既往的,智能转换器
if (this.conversionService != null) {
dataBinder.setConversionService(this.conversionService);
}
// 省略......
// 获取松散的属性匹配key
Iterable<String> relaxedTargetNames = getRelaxedTargetNames();
Set<String> names = getNames(relaxedTargetNames);
// 带全局配置的PropertySourcesPropertyValues 对象
PropertyValues propertyValues = getPropertySourcesPropertyValues(names,
relaxedTargetNames);
// 注入到配置类的属性中
dataBinder.bind(propertyValues);
if (this.validator != null) {
// 校验对象
dataBinder.validate();
}
// 是否抛valid异常
checkForBindingErrors(dataBinder);
}
这里需要注意的是RelaxedDataBinder,提供松散的匹配机制,智能化的注入到配置属性中,黑魔法!
默认的松散匹配关键类:DefaultPropertyNamePatternsMatcher、RelaxedNames
获取配置项的方法:getPropertySourcesPropertyValues
// RelaxedNames 构造函数执行时,递归穷举所有可能的松散配置
private void initialize(String name, Set<String> values) {
if (values.contains(name)) {
return;
}
for (Variation variation : Variation.values()) {
for (Manipulation manipulation : Manipulation.values()) {
String result = name;
result = manipulation.apply(result);
result = variation.apply(result);
values.add(result);
// 递归
initialize(result, values);
}
}
}