欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-05-07 18:57:32
1EnableConfigurationProperties 属性配置启动流程图 EnableConfigurationProperties,在SpringBoot的注释中是这样说明的:为带有@ConfigurationProperties注解的Bean提供有效的支持。这个注解可以提供一种方便的方式来将带有@ConfigurationProperties注解的类注入为Spring容器的Bean。核心: A:ConfigurationPropertiesBeanRegist......

1 EnableConfigurationProperties 属性配置启动流程图

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

 核心:

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

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

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

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'}%

 

本文地址:https://blog.csdn.net/qfzhangwei/article/details/107284997