【SprinBoot】EnableConfigurationProperties 注解原理和使用(2.0.6版本)

1 EnableConfigurationProperties 属性配置启动流程图

     EnableConfigurationProperties,在SpringBoot的注释中是这样说明的:为带有@ConfigurationProperties注解的Bean提供有效的支持。这个注解可以提供一种方便的方式来将带有@ConfigurationProperties注解的类注入为Spring容器的Bean。 

 核心:

     A: ConfigurationPropertiesBeanRegistrar 将@EnableConfigurationProperties 的value数组Type注入容器    

     B: ConfigurationPropertiesBindingPostProcessor会对标注@ConfigurationProperties注解的Bean进行属性值的配置

2 详细的分析流程:  

  2.1 boot 注解自动配置启动
   基于配置文件,以及SpringBoot提供的自动配置对对象进行初始化应用。(配置文件:application.properties)Spring Boot 在启动时会去依赖的 Starter 包中寻找 resources/META-INF/spring.factories 文件,然后根据文件中配置的 Jar 包去扫描项目所依赖的 Jar 包。根据 spring.factories 配置加载 AutoConfigure 类, 根据 @Conditional 注解的条件,进行自动配置并将 Bean 注入 Spring Context。Spring Boot 在启动的时候,按照约定去读取 Spring Boot Starter 的配置信息,再根据配置信息对资源进行初始化,并注入到 Spring 容器中。这样 Spring Boot 启动完毕后,就已经准备好了一切资源,使用过程中直接注入对应 Bean 资源即可

   2.2 一句话总结

    @SpringBootApplication = [@Configuration @ComponentScan @EnableAutoConfiguration] 其中 @EnableAutoConfiguration 是实现自动配置的入口,该注解又通过 @Import 注解导入了AutoConfigurationImportSelector,在该类中加载 META-INF/spring.factories 的配置信息。然后筛选出以 EnableAutoConfiguration 为 key 的数据,加载到 IOC 容器中,实现自动配置功能!  

  2.3 spring.factories文件

      在本地仓库下:.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.0.6.RELEASE/spring-boot-autoconfigure-2.0.6.RELEASE.jar!/META-INF/spring.factories。EnableAutoConfiguration 为 key 的列表,逐一加载,其中包含
例如 配置文件中包含:

 

org.springframework.boot.autoconfigure.EnableAutoConfiguration=[...,org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
,...]

 

他的作用就是:Automatically binds and validates any bean annotated with @ConfigurationProperties。这个类没有任何内容,它其实只是一个标识性的类,用来标识ConfigurationProperties自动配置,重要的就是@Configuration和@EnableConfigurationProperties 。这个类在SpringBoot中唯一被引用到的位置是在spring.factories中。所以ConfigurationPropertiesAutoConfiguration会被加载到 IOC 容器中。 ConfigurationPropertiesAutoConfiguration加载时,会解析@EnableConfigurationProperties 注解,通过@Import注解导入了EnableConfigurationPropertiesImportSelector,这个类也会被加载(org.springframework.context.annotation.ConfigurationClassParser#processImports )实例化,然后调用它的selectImports方法。selectImports方法将返回 ConfigurationPropertiesBindingPostProcessorRegistrar 和 ConfigurationPropertiesBeanRegistrar 全类限定名。 

public class ConfigurationPropertiesBindingPostProcessorRegistrar implements ImportBeanDefinitionRegistrar 实现了ImportBeanDefinitionRegistrar接口,将会在(org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions)调用registerBeanDefinitions方法;最终 ConfigurationPropertiesBindingPostProcessor 注入到容器,而就是它会对标注 @ConfigurationProperties 注解的Bean进行属性值的配置(因为org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor 实现了org.springframework.beans.factory.config.BeanPostProcessor接口单独对 ConfigurationProperties 注解进行bind处理)。

ConfigurationPropertiesBeanRegistrar 实现ImportBeanDefinitionRegistrar扩展点,将@EnableConfigurationProperties 的value 注入容器中,throw if type no @ConfigurationProperties。

其他配置类举例:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=[...,org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
,...] 

那么就会加载EmbeddedWebServerFactoryCustomizerAutoConfiguration到IOC容器中。而EmbeddedWebServerFactoryCustomizerAutoConfiguration类有 @EnableConfigurationProperties(ServerProperties.class) 注解
。就会利用上线的两个核心类将 ServiceProperties 注入到容器中。
 

3  以tomcat server.tomcat.background-processor-delay 配置为例debug

@Configuration
@ConditionalOnWebApplication
@EnableConfigurationProperties(ServerProperties.class)
public class EmbeddedWebServerFactoryCustomizerAutoConfiguration {

	/**
	 * Nested configuration if Tomcat is being used.
	 */
	@Configuration
	@ConditionalOnClass({ Tomcat.class, UpgradeProtocol.class })
	public static class TomcatWebServerFactoryCustomizerConfiguration {
	    ...
	}


}


// 创建构造参数
org.springframework.beans.factory.support.ConstructorResolver#createArgumentArray


// 断点:name.string.equalsIgnoreCase("server.tomcat.background-processor-delay")
org.springframework.boot.context.properties.bind.Binder#bindObject  获取tomcat容器定时刷新间隔


// bind 断点 propertyName.equalsIgnoreCase("background-processor-delay") || propertyName.equalsIgnoreCase("backgroundProcessorDelay")
org.springframework.boot.context.properties.bind.JavaBeanBinder#bind

// 断点: property.name.equalsIgnoreCase("timeout") 获取redis的超时时间
org.springframework.boot.context.properties.bind.JavaBeanBinder#bind


// convert   23S->Duration
org.springframework.core.convert.support.GenericConversionService#convert(java.lang.Object, org.springframework.core.convert.TypeDescriptor, org.springframework.core.convert.TypeDescriptor)

// 对象属性的对比  这个命名好厉害
org.springframework.util.ObjectUtils#nullSafeEquals 

// 可以获取到系统变量 线程断点值 source.name.equalsIgnoreCase("systemEnvironment")
// applicationConfig: [classpath:/application-prod.properties]  可获取自定义配置环境变量
org.springframework.boot.context.properties.source.SpringConfigurationPropertySources#adapt

 

4 使用@EnableConfigurationProperties实现自定义的配置属性(标准做法)

(其实如果AppProperties上加上@Component 只用1 3 两个类也可以)

// 1 配置属性类
@Data
@ConfigurationProperties(prefix = "my.app",ignoreUnknownFields = true)
public class AppProperties {
    private String appName;
    private String appVersion;

    @Override
    public String toString() {
        return "AppProperties{" +
                "appName='" + appName + '\'' +
                ", appVersion='" + appVersion + '\'' +
                '}';
    }
}

// 2 配置启动类
@Configuration// 或 @Component
@EnableConfigurationProperties(value ={ AppProperties.class })
public class MyAppStartor {
}

// 3 测试类
@RestController
public class PropertiesConfigurationController {


    @Autowired
    @Lazy
    private AppProperties appProperties;

    @GetMapping("/index")
    public String getProperties(){
        return appProperties.toString();
    }
}

// 4 配置文件
my.app.appName=zwwAPP
my.app.appVersion=1.0.0


// 5 输出
➜  ~ curl -X GET 127.0.0.1:8080/index
AppProperties{appName='zwwAPP', appVersion='1.0.0'}%

 

你可能感兴趣的:(springboot,注解)