前言
@EnableConfigurationProperties注解的使用,请移步相关博文:@EnableConfigurationProperties注解使用
前置知识
@Import注解作用简述
注入的类一般继承 ImportSelector 或者 ImportBeanDefinitionRegistrar 接口
- 继承ImportSelector接口:会在解析阶段执行 selectImports 方法,方法返回的类名数组,会被实例化成指定类型的Bean
- 继承ImportBeanDefinitionRegistrar接口:会在解析阶段执行 registerBeanDefinitions 方法
BeanDefinition
BeanDefinition是bean的建模对象,Spring根据BeanDefinition设置的相关属性实例化Bean,实例化bean的方式及优先级如下:
- 通过 supplier 创建
- 通过 factoryMethod 创建
- 其他 (默认构造方法、指定构造方法等)
详情请移步相关博文 : Spring之BeanDefinition
源码解析
@EnableConfigurationProperties注解源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EnableConfigurationPropertiesRegistrar.class)
public @interface EnableConfigurationProperties {
/**
* The bean name of the configuration properties validator.
* @since 2.2.0
*/
String VALIDATOR_BEAN_NAME = "configurationPropertiesValidator";
/**
* Convenient way to quickly register
* {@link ConfigurationProperties @ConfigurationProperties} annotated beans with
* Spring. Standard Spring Beans will also be scanned regardless of this value.
* @return {@code @ConfigurationProperties} annotated beans to register
*/
Class<?>[] value() default {};
}
综上所述,Spring会在解析阶段执行 EnableConfigurationPropertiesRegistrar 的 registerBeanDefinitions 方法。
registerBeanDefinitions
- registerInfrastructureBeans
- registerMethodValidationExcludeFilter
- ConfigurationPropertiesBeanRegistrar#register
registerInfrastructureBeans
ConfigurationPropertiesBindingPostProcessor.register
如果BeanFactory中不存在一个名称为 org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor的 BeanDefinition,则注册一个名称为 org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor,类型为 ConfigurationPropertiesBindingPostProcessor.class 的 BeanDefinition
ConfigurationPropertiesBinder.register
如果BeanFactory中不存在一个名称为 org.springframework.boot.context.internalConfigurationPropertiesBinderFactory 的 BeanDefinition,则注册一个名称为 org.springframework.boot.context.internalConfigurationPropertiesBinderFactory,类型为 ConfigurationPropertiesBinder.Factory.class 的BeanDefinition
如果BeanFactory中不存在一个名称为 org.springframework.boot.context.internalConfigurationPropertiesBinder 的 BeanDefinition,则注册一个名称为 org.springframework.boot.context.internalConfigurationPropertiesBinder,InstanceSupplier 为 ConfigurationPropertiesBinder.Factory.class 的 create 方法的 BeanDefinition
registerInfrastructureBeans方法小结
registerInfrastructureBeans方法最终会注册三个BeanDefinition,名称分别为:
- org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor
- org.springframework.boot.context.internalConfigurationPropertiesBinderFactory
- org.springframework.boot.context.internalConfigurationPropertiesBinder
registerMethodValidationExcludeFilter
如果BeanFactory中不存在一个名称为 org.springframework.boot.context.properties.EnableConfigurationPropertiesRegistrar.methodValidationExcludeFilter 的 BeanDefinition,则注册一个名称为 org.springframework.boot.context.properties.EnableConfigurationPropertiesRegistrar.methodValidationExcludeFilter,InstanceSupplier 为 MethodValidationExcludeFilter.byAnnotation(ConfigurationProperties.class) 的 BeanDefinition
ConfigurationPropertiesBeanRegistrar#register
如果@EnableConfigurationProperties注解配置了value属性,SpringBoot会以类的全限定名为名称,以value指定的类型为BeanClass构建BeanDefinition对象并注册到Spring中。如果value属性指定类的构造方法存在 @ConstructorBinding 注解,则以指定构造方法实例化对象。
registerBeanDefinitions方法小结
registerBeanDefinitions方法内部有多个方法调用,默认情况下,registerInfrastructureBeans方法会注册三个BeanDefinition,registerMethodValidationExcludeFilter 方法会注册一个BeanDefinition。如果 @EnableConfigurationProperties 注解指定了value,还会额外注册多个BeanDefinition。我们需要注意的是registerInfrastructureBeans方法注册的三个BeanDefinition,其中一个类型是 ConfigurationPropertiesBindingPostProcessor,这是一个BeanPostProcessor,默认情况下的属性绑定都是通过其 postProcessBeforeInitialization 方法完成的。由上述理论,我们可以得出以下结论:
- @EnableConfigurationProperties指定value
- @EnableConfigurationProperties + @ConfigurationProperties 完成属性绑定 (已手动注册相关BeanDefinition)
- 存在 @ConstructorBinding 注解标记的构造方法
- 以指定构造方法实例化对象
- 不存在 @ConstructorBinding 注解标记的构造方法
- 以默认构造方法实例化对象
- 存在 @ConstructorBinding 注解标记的构造方法
- @EnableConfigurationProperties + @ConfigurationProperties 完成属性绑定 (已手动注册相关BeanDefinition)
- @EnableConfigurationProperties未指定value
- @EnableConfigurationProperties + @ConfigurationProperties + @Component 完成属性绑定 (需要添加@Component注解被扫描解析成BeanDefinition)
- 以默认构造方法实例化对象
- @EnableConfigurationProperties + @ConfigurationProperties + @Component 完成属性绑定 (需要添加@Component注解被扫描解析成BeanDefinition)
属性绑定
以默认构造方法实例化对象
通过 ConfigurationPropertiesBindingPostProcessor 的 postProcessBeforeInitialization 方法绑定属性
以指定构造方法实例化对象
通过 ConfigurationPropertiesBeanRegistrar 的 createValueObject 方法绑定属性