启用ConfigurationProperties注解,EnableConfigurationProperties注解通过import导入EnableConfigurationPropertiesImportSelector选择器
value:类型为class数组,如果指定了value属性,则EnableConfigurationPropertiesImportSelector选择器会额外注册一个ConfigurationPropertiesBeanRegistrar bean。否则仅注册ConfigurationPropertiesBindingPostProcessorRegistrar bean
作用就跟它的名字一毛一样,注册一个ConfigurationPropertiesBean的定义至上下文,如果value属性指定的bean存在ConfigurationProperties注解,则注册至上下文的bean名称命名规则为ConfigurationProperties前缀+type.getName;否则直接取类型名称作为bean的名称。问题:为什么要注册value中指定的BeanDefinition至上下文?暂不讨论继续往下看。
作用也跟名称一毛一样,但会额外做件事就是将ConfigurationBeanFactoryMetaData也注册至上下文,当且也把ConfigurationPropertiesBindingPostProcessor注册至上下文
该类实现了BeanFactoryPostProcessor接口,也就是说在工厂创建完成后会回调它的postProcessBeanFactory执行一些后置动作处理。
缓存了存在工厂方法的bean。问题:缓存存在工厂方法的bean定义的用处是什么?
该类实现了InitializingBean接口,自身初始化完成时回调,如果工厂存在PropertySourcesPlaceholderConfigurer bean则使用该配置类的配置源getAppliedPropertySources;否则使用当前环境中的配置源getPropertySources。如果validator为空则从工厂中获取configurationPropertiesValidator bean作为配置校验类;如果conversionService为空则获取工厂中的conversionService bean作为转换类
自身属性的输入校验:ConfigurationPropertiesBinding,注入的该类型bean必须由ConfigurationProperties注解配置
@Autowired(required = false)
@ConfigurationPropertiesBinding
public void setConverters(List> converters) {
this.converters = converters;
}
@Autowired(required = false)
@ConfigurationPropertiesBinding
public void setGenericConverters(List converters) {
this.genericConverters = converters;
}
该类同时实现了BeanPostProcessor接口即在上下文bean初始化的前后增加了回调动作,在bean初始化后是空实现什么都没干,在bean初始化前的对bean进行前置的一些加工
postProcessBeforeInitialization前置动作
// 默认转换器
converterRegistry.addConverterFactory(new NumberToNumberConverterFactory());
converterRegistry.addConverterFactory(new StringToNumberConverterFactory());
converterRegistry.addConverter(Number.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new StringToCharacterConverter());
converterRegistry.addConverter(Character.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new NumberToCharacterConverter());
converterRegistry.addConverterFactory(new CharacterToNumberFactory());
converterRegistry.addConverter(new StringToBooleanConverter());
converterRegistry.addConverter(Boolean.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverterFactory(new StringToEnumConverterFactory());
converterRegistry.addConverter(new EnumToStringConverter((ConversionService) converterRegistry));
converterRegistry.addConverterFactory(new IntegerToEnumConverterFactory());
converterRegistry.addConverter(new EnumToIntegerConverter((ConversionService) converterRegistry));
converterRegistry.addConverter(new StringToLocaleConverter());
converterRegistry.addConverter(Locale.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new StringToCharsetConverter());
converterRegistry.addConverter(Charset.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new StringToCurrencyConverter());
converterRegistry.addConverter(Currency.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new StringToPropertiesConverter());
converterRegistry.addConverter(new PropertiesToStringConverter());
converterRegistry.addConverter(new StringToUUIDConverter());
converterRegistry.addConverter(UUID.class, String.class, new ObjectToStringConverter());
converterRegistry.addConverter(new ArrayToCollectionConverter(conversionService));
converterRegistry.addConverter(new CollectionToArrayConverter(conversionService));
converterRegistry.addConverter(new ArrayToArrayConverter(conversionService));
converterRegistry.addConverter(new CollectionToCollectionConverter(conversionService));
converterRegistry.addConverter(new MapToMapConverter(conversionService));
converterRegistry.addConverter(new ArrayToStringConverter(conversionService));
converterRegistry.addConverter(new StringToArrayConverter(conversionService));
converterRegistry.addConverter(new ArrayToObjectConverter(conversionService));
converterRegistry.addConverter(new ObjectToArrayConverter(conversionService));
converterRegistry.addConverter(new CollectionToStringConverter(conversionService));
converterRegistry.addConverter(new StringToCollectionConverter(conversionService));
converterRegistry.addConverter(new CollectionToObjectConverter(conversionService));
converterRegistry.addConverter(new ObjectToCollectionConverter(conversionService));
if (streamAvailable) {
converterRegistry.addConverter(new StreamConverter(conversionService));
}
converterRegistry.addConverter(new ByteBufferConverter((ConversionService) converterRegistry));
if (jsr310Available) {
Jsr310ConverterRegistrar.registerJsr310Converters(converterRegistry);
}
converterRegistry.addConverter(new ObjectToObjectConverter());
converterRegistry.addConverter(new IdToEntityConverter((ConversionService) converterRegistry));
converterRegistry.addConverter(new FallbackObjectToStringConverter());
if (javaUtilOptionalClassAvailable) {
converterRegistry.addConverter(new ObjectToOptionalConverter((ConversionService) converterRegistry));
}
// registry:RelaxedDataBinder
public void registerCustomEditors(PropertyEditorRegistry registry) {
ResourceEditor baseEditor = new ResourceEditor(this.resourceLoader, this.propertyResolver);
doRegisterEditor(registry, Resource.class, baseEditor);
doRegisterEditor(registry, ContextResource.class, baseEditor);
doRegisterEditor(registry, InputStream.class, new InputStreamEditor(baseEditor));
doRegisterEditor(registry, InputSource.class, new InputSourceEditor(baseEditor));
doRegisterEditor(registry, File.class, new FileEditor(baseEditor));
if (pathClass != null) {
doRegisterEditor(registry, pathClass, new PathEditor(baseEditor));
}
doRegisterEditor(registry, Reader.class, new ReaderEditor(baseEditor));
doRegisterEditor(registry, URL.class, new URLEditor(baseEditor));
ClassLoader classLoader = this.resourceLoader.getClassLoader();
doRegisterEditor(registry, URI.class, new URIEditor(classLoader));
doRegisterEditor(registry, Class.class, new ClassEditor(classLoader));
doRegisterEditor(registry, Class[].class, new ClassArrayEditor(classLoader));
if (this.resourceLoader instanceof ResourcePatternResolver) {
doRegisterEditor(registry, Resource[].class,
new ResourceArrayPropertyEditor((ResourcePatternResolver) this.resourceLoader, this.propertyResolver));
}
}
1. 初始值
2. HYPHEN_TO_UNDERSCORE:横线转下划线
3. UNDERSCORE_TO_PERIOD:下划线转点(.)
4. PERIOD_TO_UNDERSCORE:点转下划线
5. CAMELCASE_TO_UNDERSCORE:驼峰转下划线
6. CAMELCASE_TO_HYPHEN:驼峰转横线
7. SEPARATED_TO_CAMELCASE:横线、点、下划线转驼峰
8. CASE_INSENSITIVE_SEPARATED_TO_CAMELCASE:横线、点、下划线转驼峰(忽略大小写,全部转为小写)
0 = "rocketmq.consume-check-type"
1 = "rocketmq_consume-check-type"
2 = "rocketmq.consume_check_type"
3 = "rocketmq_consume_check_type"
4 = "rocketmq.consumeCheckType"
5 = "rocketmq_consumeCheckType"
6 = "rocketmq.consumechecktype"
7 = "rocketmq_consumechecktype"
8 = "rocketmq.CONSUME-CHECK-TYPE"
9 = "rocketmq_CONSUME-CHECK-TYPE"
10 = "rocketmq.CONSUME_CHECK_TYPE"
11 = "rocketmq_CONSUME_CHECK_TYPE"
12 = "rocketmq.CONSUMECHECKTYPE"
13 = "rocketmq_CONSUMECHECKTYPE"
14 = "ROCKETMQ.consume-check-type"
15 = "ROCKETMQ_consume-check-type"
16 = "ROCKETMQ.consume_check_type"
17 = "ROCKETMQ_consume_check_type"
18 = "ROCKETMQ.consumeCheckType"
19 = "ROCKETMQ_consumeCheckType"
20 = "ROCKETMQ.consumechecktype"
21 = "ROCKETMQ_consumechecktype"
22 = "ROCKETMQ.CONSUME-CHECK-TYPE"
23 = "ROCKETMQ_CONSUME-CHECK-TYPE"
24 = "ROCKETMQ.CONSUME_CHECK_TYPE"
25 = "ROCKETMQ_CONSUME_CHECK_TYPE"
26 = "ROCKETMQ.CONSUMECHECKTYPE"
27 = "ROCKETMQ_CONSUMECHECKTYPE"
28 = "rocketmq.consume-thread-max"
29 = "rocketmq_consume-thread-max"
30 = "rocketmq.consume_thread_max"
31 = "rocketmq_consume_thread_max"
32 = "rocketmq.consumeThreadMax"
33 = "rocketmq_consumeThreadMax"
34 = "rocketmq.consumethreadmax"
35 = "rocketmq_consumethreadmax"
36 = "rocketmq.CONSUME-THREAD-MAX"
37 = "rocketmq_CONSUME-THREAD-MAX"
38 = "rocketmq.CONSUME_THREAD_MAX"
39 = "rocketmq_CONSUME_THREAD_MAX"
40 = "rocketmq.CONSUMETHREADMAX"
41 = "rocketmq_CONSUMETHREADMAX"
42 = "ROCKETMQ.consume-thread-max"
43 = "ROCKETMQ_consume-thread-max"
44 = "ROCKETMQ.consume_thread_max"
45 = "ROCKETMQ_consume_thread_max"
46 = "ROCKETMQ.consumeThreadMax"
47 = "ROCKETMQ_consumeThreadMax"
48 = "ROCKETMQ.consumethreadmax"
49 = "ROCKETMQ_consumethreadmax"
50 = "ROCKETMQ.CONSUME-THREAD-MAX"
51 = "ROCKETMQ_CONSUME-THREAD-MAX"
52 = "ROCKETMQ.CONSUME_THREAD_MAX"
53 = "ROCKETMQ_CONSUME_THREAD_MAX"
54 = "ROCKETMQ.CONSUMETHREADMAX"
55 = "ROCKETMQ_CONSUMETHREADMAX"
56 = "rocketmq.consume-thread-min"
57 = "rocketmq_consume-thread-min"
58 = "rocketmq.consume_thread_min"
59 = "rocketmq_consume_thread_min"
60 = "rocketmq.consumeThreadMin"
61 = "rocketmq_consumeThreadMin"
62 = "rocketmq.consumethreadmin"
63 = "rocketmq_consumethreadmin"
64 = "rocketmq.CONSUME-THREAD-MIN"
65 = "rocketmq_CONSUME-THREAD-MIN"
66 = "rocketmq.CONSUME_THREAD_MIN"
67 = "rocketmq_CONSUME_THREAD_MIN"
68 = "rocketmq.CONSUMETHREADMIN"
69 = "rocketmq_CONSUMETHREADMIN"
70 = "ROCKETMQ.consume-thread-min"
71 = "ROCKETMQ_consume-thread-min"
72 = "ROCKETMQ.consume_thread_min"
73 = "ROCKETMQ_consume_thread_min"
74 = "ROCKETMQ.consumeThreadMin"
75 = "ROCKETMQ_consumeThreadMin"
76 = "ROCKETMQ.consumethreadmin"
77 = "ROCKETMQ_consumethreadmin"
78 = "ROCKETMQ.CONSUME-THREAD-MIN"
79 = "ROCKETMQ_CONSUME-THREAD-MIN"
80 = "ROCKETMQ.CONSUME_THREAD_MIN"
81 = "ROCKETMQ_CONSUME_THREAD_MIN"
82 = "ROCKETMQ.CONSUMETHREADMIN"
83 = "ROCKETMQ_CONSUMETHREADMIN"
84 = "rocketmq.consumer-group-name"
85 = "rocketmq_consumer-group-name"
86 = "rocketmq.consumer_group_name"
87 = "rocketmq_consumer_group_name"
88 = "rocketmq.consumerGroupName"
89 = "rocketmq_consumerGroupName"
90 = "rocketmq.consumergroupname"
91 = "rocketmq_consumergroupname"
92 = "rocketmq.CONSUMER-GROUP-NAME"
93 = "rocketmq_CONSUMER-GROUP-NAME"
94 = "rocketmq.CONSUMER_GROUP_NAME"
95 = "rocketmq_CONSUMER_GROUP_NAME"
96 = "rocketmq.CONSUMERGROUPNAME"
97 = "rocketmq_CONSUMERGROUPNAME"
98 = "ROCKETMQ.consumer-group-name"
99 = "ROCKETMQ_consumer-group-name"
100 = "ROCKETMQ.consumer_group_name"
101 = "ROCKETMQ_consumer_group_name"
102 = "ROCKETMQ.consumerGroupName"
103 = "ROCKETMQ_consumerGroupName"
104 = "ROCKETMQ.consumergroupname"
105 = "ROCKETMQ_consumergroupname"
106 = "ROCKETMQ.CONSUMER-GROUP-NAME"
107 = "ROCKETMQ_CONSUMER-GROUP-NAME"
108 = "ROCKETMQ.CONSUMER_GROUP_NAME"
109 = "ROCKETMQ_CONSUMER_GROUP_NAME"
110 = "ROCKETMQ.CONSUMERGROUPNAME"
111 = "ROCKETMQ_CONSUMERGROUPNAME"
112 = "rocketmq.name-server-addr"
113 = "rocketmq_name-server-addr"
114 = "rocketmq.name_server_addr"
115 = "rocketmq_name_server_addr"
116 = "rocketmq.nameServerAddr"
117 = "rocketmq_nameServerAddr"
118 = "rocketmq.nameserveraddr"
119 = "rocketmq_nameserveraddr"
120 = "rocketmq.NAME-SERVER-ADDR"
121 = "rocketmq_NAME-SERVER-ADDR"
122 = "rocketmq.NAME_SERVER_ADDR"
123 = "rocketmq_NAME_SERVER_ADDR"
124 = "rocketmq.NAMESERVERADDR"
125 = "rocketmq_NAMESERVERADDR"
126 = "ROCKETMQ.name-server-addr"
127 = "ROCKETMQ_name-server-addr"
128 = "ROCKETMQ.name_server_addr"
129 = "ROCKETMQ_name_server_addr"
130 = "ROCKETMQ.nameServerAddr"
131 = "ROCKETMQ_nameServerAddr"
132 = "ROCKETMQ.nameserveraddr"
133 = "ROCKETMQ_nameserveraddr"
134 = "ROCKETMQ.NAME-SERVER-ADDR"
135 = "ROCKETMQ_NAME-SERVER-ADDR"
136 = "ROCKETMQ.NAME_SERVER_ADDR"
137 = "ROCKETMQ_NAME_SERVER_ADDR"
138 = "ROCKETMQ.NAMESERVERADDR"
139 = "ROCKETMQ_NAMESERVERADDR"
140 = "rocketmq.subscribes"
141 = "rocketmq_subscribes"
142 = "rocketmq.SUBSCRIBES"
143 = "rocketmq_SUBSCRIBES"
144 = "ROCKETMQ.subscribes"
145 = "ROCKETMQ_subscribes"
146 = "ROCKETMQ.SUBSCRIBES"
147 = "ROCKETMQ_SUBSCRIBES"
构造器中遍历处理配置源:processPropertySource
遍历source的所有属性名,即MapPropertySource.getPropertyNames,返回properties的keySet
如果匹配器匹配到配置源的属性名则获取配置value,构建属性值并缓存
// Pattern COLLECTION_PROPERTY = Pattern.compile("\\[(\\d+)\\](\\.\\S+)?");
// COLLECTION_PROPERTY即集合类型的属性,例如:
// spring.diamonds[0].data-id=mydata0
// spring.diamonds[0].group-id=mygroup0
// spring.diamonds[1].data-id=mydata1
// spring.diamonds[1].group-id=mygroup1
private PropertyValue putIfAbsent(String propertyName, Object value,
PropertySource<?> source) {
if (value != null && !this.propertyValues.containsKey(propertyName)) {
PropertySource<?> collectionOwner = this.collectionOwners.putIfAbsent(
COLLECTION_PROPERTY.matcher(propertyName).replaceAll("[]"), source);
if (collectionOwner == null || collectionOwner == source) {
PropertyValue propertyValue = new OriginCapablePropertyValue(propertyName,
value, propertyName, source);
this.propertyValues.put(propertyName, propertyValue);
return propertyValue;
}
}
return null;
}
com.gallant[0].user.[id]=1;
com.gallant[1].user.[name]=superman;
上面的配置属性
6. com,gallant,user:PropertyNode类型节点
7. [0]:ArrayIndexNode类型节点
8. [id]:MapIndexNode类型节点
当然是为了上下文中可以直接注入配置bean使用配置喽
因为对工厂方法定义的bean也支持属性配置的注入,如果工厂方法bean的定义上存在ConfigurationProperties注解,则该bean也可以直接使用配置值
spring.diamonds[0].data-id=ddd
spring.diamonds[0].group-id=111
spring.diamonds[1].data-id=eee
spring.diamonds[1].group-id=222
spring.diamonds['dataId']=d1
spring.diamonds['groupId']=g1