关于spring boot配置优先级的特殊之处

前言

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,……)。


© 2009-2020 Zollty.com 版权所有。渝ICP备20008982号