SpringBoot-ConfigurationProperties
写代码时,常会在代码中使用配置相关的常量。
对于这些配置常量,最佳实践是配置文件分离,即将这些配置常量写入一个配置文件中。常见的配置文件包括如properties、XML文件、JSON文件、YAML文件。这样每次修改配置时,不需要改动源文件并重新编译,也不需要通过命令行传参,只需改动配置文件中对应属性即可。而且把配置信息放在一起会使代码可读性,可维护性更好。
Java中的配置文件
Java的常用配置文件为properties文件。可以通过FileInputStream
或ClassLoader
来读取配置文件。并通过包装成Properties
对象,来解析文件中的属性。由于Java的配置文件通常位于类路径下,因此使用ClassLoader
来读取有更好的可移植性。
1 |
|
之后需要将配置文件中的属性赋值到Java类的字段上。这种配置文件和类字段映射的思想叫做配置文件驱动开发
。
但在实际开发中,一整个项目的配置信息是十分多的。如果对于每一个配置属性都显式地赋值给一个类字段,那整个赋值过程会十分繁琐。因此需要一种方式,能将配置文件自动映射到类字段上。
ConfigurationProperties
谈到Java开发就离不开Spring(SpringBoot)。Spring提供了许多常见且通用的功能和工具来简化 Java 应用程序的开发,例如上文提到的配置文件的自动映射。
在Spring当中,如果需要将配置文件映射到某个类上,那么只需要在这个类上添加@ConfigurationProperties
注解,并将这个类在Spring容器中实例化,Spring就会自动完成配置属性注入的功能。
具体实现时,通常有两种方式。
@ConfigurationProperties
+@Component
@ConfigurationProperties
+@EnableConfigurationProperties
其中@ConfigurationProperties
加在需要配置属性注入的类上,并在注解中指定配置属性的前缀。并通过@Component
将类加入到容器中。需要注意的是,通过这种方式需要确保在主配置类中开启了@ComponentScan
,并且能扫描到此类。
而Spring的默认配置文件名为application.properties
,且位于类路径的根目录下。这是Spring的默认大于配置
软件设计原则。也就是如果没特殊情况,大家都遵守这样的约定。
1 |
|
1 |
|
此处定义了MyConfiguration
类,并且包含两个字段name
,version
,字段名与配置文件中的属性键去掉前缀对应。并通过@ConfigurationProperties(prefix = "abc")
注解指定了配置文件中的前缀,这样就可以在配置文件中通过前缀组织不同配置的属性。
或者,可以使用@EnableConfigurationProperties
,添加在主配置类上,此时可以将属性注入的类上的@Component
去掉,否则容器中会有两个MyConfiguration
的Bean。
1 |
|
1 |
|
其中,@EnableConfigurationProperties
中指定需要开启属性注入功能的类。
但在实际过程中,出现了一些问题。
遇到的问题
在实际学习过程中,属性注入一直失败。最后排查发现,对于属性注入的类,还需要配置Setter方法。这是因为配置属性注入,是通过Java反射,调用了对应的Setter方法。可以自行显示地定义Setter方法,或者使用@Data
注解,自动生成类的Getter、Setter方法。
但在定义完Setter方法后,使用@ConfigurationProperties
+
@Component
的方式配置属性注入依旧无法完成。通过对类属性打上断点,并查看调用栈,发现要使用这种方式完成配置属性注入,容器内必须要有ConfigurationPropertiesBindingPostProcessor
。这是一个BeanPostProcessor
,本质也是一个Bean,但和普通Bean的不同在于它可以参与Bean的实例化过程,以对其他Bean进行属性修改或功能增强。而在不使用@SpringBootApplication
或@EnableAutoConfiguration
的最小配置启动下,默认没有向容器中导入这个BeanPostProcessor
。

并且在调用栈中,可以观察到最后是通过反射的方式,调用Setter方法来完成了配置属性注入。

而使用@ConfigurationProperties
+
@EnableConfigurationProperties
的方式则不需要@EnableAutoConfiguration
配置项。通过调试发现,@EnableConfigurationProperties
带有@Import(EnableConfigurationPropertiesRegistrar.class)
注解,而EnableConfigurationPropertiesRegistrar
在方法registerBeanDefinitions
中,向容器中注册了ConfigurationPropertiesBindingPostProcessor
,而后被实例化以提供配置属性注入的功能。
这一部分内容很涉及框架层面的内容,暂时不准备挖的更深。总之,@EnableConfigurationProperties
本身就会向容器内导入ConfigurationPropertiesBindingPostProcessor
,因此不需要@EnableAutoConfiguration
也能完成配置属性注入工作。
总结
配置文件分离是软件部署的最佳实践,熟悉其过程和原理也是每个程序员的必修课。在Spring框架中,使用@ConfigurationProperties
来完成配置文件与类的绑定,在使用时需要指定每个类对应配置文件键的前缀。并把这个类放入容器中,以被ConfigurationPropertiesBindingPostProcessor
完成属性注入的功能。而ConfigurationPropertiesBindingPostProcessor
可以通过@EnableAutoConfiguration
或@EnableConfigurationProperties
导入。ConfigurationPropertiesBindingPostProcessor
最终是通过Java反射完成属性注入,需要调用对应的Setter方法。