@ConfigurationProperties 注解类的属性填充
1. @ConfigurationProperties 注解的使用方式
仅被@ConfigurationProperties
注解的类,不会被纳入Bean管理。因为@ConfigurationProperties
,没有包含@Component
。需要手动添加@Component
一类的注解。
或者在@EnableConfigurationProperties
注解中声明该class,这种方式下,被@ConfigurationProperties
注解的类不需要包含@Component
。但是被@EnableConfigurationProperties
注解的类要确保包含@Component
,以便被spring-boot扫描到。
2. @ConfigurationProperties 被解析的过程
当被@ConfigurationProperties
注解的Bean被实例化时,会经过org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor#postProcessBeforeInitialization
这一BeanPostProcessor
的处理。
2.1
由每个Bean都会经过这个processor处理,所以处理过程中首先会判断是否有@ConfigurationProperties
注解。执行此判断的方法是
org.springframework.boot.context.properties.ConfigurationPropertiesBean#create
。
2.2
processor内部会一直调用到org.springframework.boot.context.properties.bind.Binder#bind()
方法填充配置字段。
org.springframework.boot.context.properties.bind.Binder#findProperty
该方法会在各个ConfigurationPropertySource
中以propertyName查找对应的propertyValue,查到第一个匹配值就返回。
注
- ConfigurationPropertySource最终来自于
org.springframework.core.env.AbstractEnvironment#propertySources
,其中的PropertySource
是有序的。- 如果配置中有多个相同的配置,会以查到的第一个匹配值为最终结果。至于多个PropertySource的顺序,在下一节中说明。
@PropertySource 注解添加自定义数据源
1. @PropertySource的解析调用栈
addPropertySource:506, ConfigurationClassParser (org.springframework.context.annotation)
processPropertySource:463, ConfigurationClassParser (org.springframework.context.annotation)
doProcessConfigurationClass:280, ConfigurationClassParser (org.springframework.context.annotation)
processConfigurationClass:250, ConfigurationClassParser (org.springframework.context.annotation)
parse:199, ConfigurationClassParser (org.springframework.context.annotation)
doProcessConfigurationClass:304, ConfigurationClassParser (org.springframework.context.annotation)
processConfigurationClass:250, ConfigurationClassParser (org.springframework.context.annotation)
parse:207, ConfigurationClassParser (org.springframework.context.annotation)
parse:175, ConfigurationClassParser (org.springframework.context.annotation)
processConfigBeanDefinitions:320, ConfigurationClassPostProcessor (org.springframework.context.annotation)
postProcessBeanDefinitionRegistry:237, ConfigurationClassPostProcessor (org.springframework.context.annotation)
invokeBeanDefinitionRegistryPostProcessors:280, PostProcessorRegistrationDelegate (org.springframework.context.support)
invokeBeanFactoryPostProcessors:96, PostProcessorRegistrationDelegate (org.springframework.context.support)
invokeBeanFactoryPostProcessors:707, AbstractApplicationContext (org.springframework.context.support)
refresh:533, AbstractApplicationContext (org.springframework.context.support)
refresh:143, ServletWebServerApplicationContext (org.springframework.boot.web.servlet.context)
refresh:755, SpringApplication (org.springframework.boot)
refresh:747, SpringApplication (org.springframework.boot)
refreshContext:402, SpringApplication (org.springframework.boot)
run:312, SpringApplication (org.springframework.boot)
run:1247, SpringApplication (org.springframework.boot)
run:1236, SpringApplication (org.springframework.boot)
main:18, Application (com.jindi.search.platform)
2. @PropertySource 被解析的过程
该调用栈其实就是解析@ComponentScan
,扫描bean。
其中的 org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass
函数内发现该bean拥有@PropertySource 注解的话,会解析这个PropertySource
。
所以被@PropertySource
注解的类只要同时被@Component
注解,即被扫描识别为Bean即可成功解析。
解析完毕加入到org.springframework.core.env.AbstractEnvironment#propertySources
内的list的末尾处。
当前的解析来自于refreshContext()
方法,而application.yml
等spring惯例的配置文件早在prepareEnvironment
处就加到了propertySources
list中,所以自定义的PropertySource
优先级比较低。
3. @PropertySource 指向的配置文件的格式
@PropertySource
指向的配置文件可以使用.properties格式和.xml格式,不能使用.yml格式。
配置文件的解析依次使用
org.springframework.core.io.support.DefaultPropertySourceFactory
org.springframework.core.io.support.PropertiesLoaderUtils#loadProperties
来进行加载。其内部可以加载.properties格式和.xml格式的文件。这些方法调用中的接口,没有内置的解析.yml文件格式实现类。
application.yml
等spring惯例的配置文件可以使用.yml格式,是因为在spring-boot包中,
org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#load()
加载配置文件的方法会使用spring-boot内置的yml文件解析器。