前言
SpringBoot官方文档指明了这多种配置方式的优先级,按照从高到低排序分为……(见后文)。但经过我的测试,发现了一些不一致的情况。
有兴趣的朋友,可以根据我的这篇文章,给Spring社区提交Bug!!!
正文
今天遇到两个奇怪问题,经过不停测试,终于弄清楚了:
1、现象是 spring boot的 logging.config 配置非常特殊
假设有三个配置文件:
application-log.yml:
logging.config: classpath:logback11.xml
application-dev.yml:
logging.config: classpath:logback22.xml
application.yml:
spring.profiles.include: log
spring.profiles.active: dev
logging.config: classpath:logback33.xml
并且,第四个配置为Main函数的命令行参数:
--logging.config=classpath:logback44.xml
问(1):以上4个配置同时存在时,最终生效的logback配置为哪一个?
答:直觉告诉我,应该以命令行参数配置为准(logback44.xml)。次高优先级应该是application-dev(logback22.xml)
问(2):去掉spring.profiles.active: dev后,最终生效的是哪一个?
答:同上,logback44.xml优先级最高,logback33.xml次之。
正确答案:
只能用一句:操蛋来形容!!
测试结果为:
1、application.yml和命令行参数中的logging.config无法覆盖spring.profiles.active/include中的配置。
2、有spring.profiles.active时,以active里面的配置为准。
3、无spring.profiles.active,但是有spring.profiles.include: log时,以include的配置为准。
(多个spring.profiles.include只能合并)
因此,
(1)的答案为 application-dev(logback22.xml)
(2)的答案为 application-log(logback11.xml)
所以,
如果想覆盖上述spring.profiles.include: log(application-log.yml)中的logging.config配置,只有一个方案:
修改 spring.profiles.active,让它激活指定带有 自定义logging.config配置的yml文件。这样就能覆盖原来include中的logging.config配置了。在application.yml和命令行参数中设置logging.config配置是无效的!
2、SpringBoot官方文档指明了这多种配置方式的优先级,按照从高到低排序如下:
(1)如果使用了Devtools,则优先级最高的是在home目录下指定的Devtools全局配置文件~/.spring-boot-devtools.properties(优先级最高)。
(2)测试用例中,标注了 @TestPropertySource 配置项;
(3)测试用例中,@SpringBootTest 注解中的 properties 属性值;
(4)命令行参数;
(5)内嵌在环境变量或者系统变量中的SPRING_APPLICATION_JSON中的属性值;
(6)ServletConfig 初始化的参数;
(7)ServletContext 初始化的参数;
(8)java:comp/env 中的JNDI属性值;
(9)Java的系统变量,通过System.getProperties()方法获取;
(10)操作系统的环境变量;
(11)RandomValuePropertySource配置的${random.*}属性值;
(12)不在项目打成可执行jar包中的application-{profile}.properties或者application-{profile}.yml文件;
(13)项目打成可执行jar包中的application-{profile}.properties或者application-{profile}.yml文件;
(14)不在项目打成可执行jar包中的application.properties或者application.yml文件;
(15)项目打成可执行jar包中的application.properties或者application.yml文件;
(16)同时标注@Configuration和@PropertySource的类中,标注了@PropertySource指定的属性值;
(17)在main方法中设置的SpringApplication.setDefaultProperties值(优先级最低)。
参见官方文档:spring-boot-external-config
大家应该注意到了,官方给的这个顺序,跟我测试的优先级顺序是矛盾的。
而且官方的这个顺序中,没有提到以spring.profiles.include这种方式引入配置的顺序。
而且注意:我只测试了logging.config这个配置,也有可能是这个配置的特殊性,导致了跟spring官方提供的优先级不一致,不代表其他配置优先级也有问题。
除此之外,还有三种配置引入方式:
spring.config.location
spring.config.additional-location
spring.config.import
spring.config.activate.on-cloud-platform=kubernetes
spring.config.activate.on-profile=prod | staging
例如:
spring.config.import = optional:file:./myconfig.properties
spring.config.on-not-found = ignore
spring.config.import = optional:configtree:/etc/config/*/
看起来挺复杂,这个我也没有测试过。
参见官方文档:spring-boot-reference-profiles
没看懂的直接看结论
结论
使用SpringBoot时,不建议使用命令行参数配置和环境变量配置,因为它们的优先级 跟实际的优先级可能不一致:如果想通过命令行参数配置和环境变量配置去覆盖yml配置文件中的配置,可能达不到预期目的。
因此,建议出台一个规范,避免配置优先级问题:
spring.profiles.active配置的取值只能是 dev、test(可以分几种)、prod这几个之一,且其取值跟部署的环境一致(生产环境就只用prod,开发环境就只用dev,……)。