@ConfigurationProperties作用:将当前类属性与yml/properties配置文件中的属性进行绑定,还能通过prefix指定配置前缀。

印象中一直有@ConfigurationProperties无法注入的情况,当时换其它方法解决了,也就没在意。

而今天准备自动注入配置文件中的多个配置项目,到一个List,显然不能再用以前那种方法,会非常麻烦。
在这里插入图片描述
使用@ConfigurationProperties(prefix = “spring.redis.cluster”),一直为null。
在这里插入图片描述
那换@Value("${spring.redis.cluster.urls}")注入试试。
在这里插入图片描述
还是不行,@Value注入解析不了数据结构。

解决方法

首先,需要getter\setter方法。
其次,启动类上加上@EnableConfigurationProperties,这个注解作用就是启用对@ConfigurationProperties注解的支持。
在这里插入图片描述
注入测试:
在这里插入图片描述

原理探究

授人以鱼不如授人以渔。

为什么测试时不行?

正常启动SpringBoot时能注入的,而使用SpringBootTest启动就无效。

这个很好分析,一提到SpringBoot我们直接想到自动装配,来吧,一定能在spring-boot-autoconfigure.jar的spring.factories中找到你想要的东西(重要,知道了这一步就能任你探究SpringBoot的原理):
在这里插入图片描述
来到ConfigurationPropertiesAutoConfiguration,看到@EnableConfigurationProperties注解,也就完全验证了我们的想法。
在这里插入图片描述
也就是在@SpringBootApplication环境下,这些都给配置好了,因此@ConfigurationProperties才有效。

小结

我们在SpringBootTest测试时,有时只需要功能测试,非集成测试。此时,处于未自动装配ConfigurationPropertiesAutoConfiguration的情况,因此@ConfigurationProperties也就不会生效。

继续探究原理

  1. 且看@EnableConfigurationProperties,噢,原来只是个标记,最终配置逻辑在EnableConfigurationPropertiesRegistrar。
    在这里插入图片描述

  2. 实现了ImportBeanDefinitionRegistrar,具备动态注册Bean的功能。

  3. 动态注册了ConfigurationPropertiesBindingPostProcessor这个BeanPostProcessor,用于在Bean的初始化前后回调。
    在这里插入图片描述

  4. 启动容器,debug看看创建Bean的生命周期中干了什么。

    我写的配置类是:@ConfigurationProperties(prefix = “spring.redis.cluster”) RedisConfig。

    下面是创建RedisConfig这个Bean的调用栈。
    在这里插入图片描述 在这里插入图片描述
    在这里插入图片描述
    看下面代码,有个ConfigurationProperties,也就是在这一步会解析需要注入配置的Bean上写的@ConfigurationProperties。从而根据其prefix找到yml中属性,注入到Bean实例的属性中。在这里插入图片描述

  5. bind方法调用后,被创建的Bean的实例的属性上也就有值了。
    在这里插入图片描述

小结

  1. @EnableConfigurationProperties的原理是@Import了EnableConfigurationPropertiesRegistrar。其功能就是读取配置文件并转换为bean。这就是为什么能注入配置文件中复杂数据结构的原因。
  2. 实现EnableConfigurationPropertiesRegistrar利用ImportBeanDefinitionRegistrar动态注册了ConfigurationPropertiesBindingPostProcessor。
  3. 在getBean->createBean->applyBeanPostProcessorsBeforeInitialization->bind方法中根据当前实例化的Bean上的@ConfigurationProperties完成注册。

    关键点:applyBeanPostProcessorsBeforeInitialization。
    该方法会循环调用了所有BeanPostProcessor的postProcessBeforeInitialization方法,也就包含了ConfigurationPropertiesBindingPostProcessor。

使用方法

利用@EnableConfigurationProperties将配置解析为自定义的Bean

先解读一下源码中对该类的注释:
在这里插入图片描述

  1. 首先开头描述了是为了启用以对@ConfigurationProperties注解的支持。且它能把properties或者yml配置文件转化为bean。
    关键点:既然是Bean,那么配置文件就能在Spring项目中能扫描到的地方任意注入。
  2. value方法,以便我们直接指定一个JavaBean,JavaBean需要被@ConfigurationProperties注解,最终JavaBean被返回成一个已被注册到IoC容器的SpringBean。

案例:

  1. 配置文件
    在这里插入图片描述
  2. 启动类或配置类中配置在这里插入图片描述
  3. Properties JavaBean类。指定prefix,告诉spring从配置的文件的class.student开始,将下面的key-value解析对应到Student类属性上(key为对应属性名,value对应属性值)。
    在这里插入图片描述
  4. 通过上面的操作JavaBean Student的实例会被Spring给实例化,并被赋入yml文件中自定义的值再放入IoC容器。此刻就是一个SpringBean,我们可以在项目中任何能被扫描到的地方使用它。
    在这里插入图片描述

注:

显示在@EnableConfigurationProperties中指定Student或或不指定的使用区别?

个人心得:
如果已经在项目中启用了@EnableConfigurationProperties,那么在@EnableConfigurationProperties注解中指定或不指定一个PropertiesBean效果其实都差不多。

那为何声明情况下建议使用?
我个人是偏向于在编写一个自定义的starter时使用,例如:@EnableConfigurationProperties(XxxProperties.class)。

优点:

  • 一,防止项目漏写@EnableConfigurationProperties;
  • 二,显示的指定配置XxxPropertiesBean,便于代码的可读性提升。
  • 三,XxxProperties上一般只有@ConfigurationProperties(prefix = “xxx.x”),它是不会被Spring作为Bean注入属性并自动注入IoC的。因此写@EnableConfigurationProperties({XxxProperties.class}),就相当于给XxxProperties类上加了一个@Component,它会被自动装入属性并作为一个IoC中的Bean。
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐