SpringBoot的配置优先级是怎样的?
SpringBoot的配置优先级是怎样的?
大家应该知道一个应用为啥需要有配置吧?就是为了不写死代码,让有些变量可以独立于代码之外去修改,毕竟改配置的成本是远低于改代码的。
早期大家都约定这个配置文件以*.properties形式存在,应用启动时需要读取一堆properties文件,但这存在几个问题:
- 文件名不统一,文件位置也不统一
- 单元测试的时候也需要改配置,但又不想动
src/main/下的配置 - 某些情况下,大部分服务器保持默认配置即可,某些机器要用特殊配置怎么弄
- 还有这应该是个技术组件干的活,为啥要每个程序自己去读配置
于是乎SpringBoot干了一件事儿:把配置抽象包装了一下,彻底给丫统一了。
统一文件名
SpringBoot一直秉承着约定优于配置的思想。
首先,配置文件的名字,大家都叫application.properties,后来又出现了一个yml格式看起来更优雅,所以叫application.yml也行,就这两种叫法。
提示
可以通过修改spring.config.name属性来改变配置文件名
配置文件放在哪
就放在src/main/resources目录下,打包的时候默认会打到classpath根目录。
这样文件名读取这个工作SpringBoot就可以自动帮你做了。
提示
通过spring.config.location属性可以调整配置文件的读取位置,不过建议不要改。
注意
spring.config.location和spring.config.name都不能写在配置文件里,而是写在命令行参数或环境变量中,总之必须先让程序读到这两个参数然后才能找到配置文件。
PropertySource
SpringBoot还干了一件事,就是把所有能放配置的地方都进行了抽象,起了个名字叫PropertySource。
这就灵活多变了,你只需按规定,把配置放到该放的地方,SpringBoot就会自动帮你读,帮你管理。上面不是说配置统一放在src/main/resources目录下吗?在SpringBoot下就不是了,SpringBoot约定了有这么些地方可以放配置:
- 家目录下的
~/.spring-boot-devtools.properties文件(如果开启了devtools就生效,这个是用于开发的时候临时调整变量用的) - 用
@TestPropertySource标记的类,这个是在单测的时候 - 测试目录下的properties,也就是
src/test/resources目录 - 命令行参数,就是启动时
java -jar xxxx.jar --......后面跟着的一堆参数 - SPRING_APPLICATION_JSON属性,可以用
--spring.application.json='{"name":"test"}'方式在命令行设置一串json属性 - ServletConfig初始化参数,可以先忽略,现在很少手动去配这个
- ServletContext初始化参数,可以先忽略,现在很少手动去配这个
- 来自于
java:comp/env的JNDI属性,聊到JNDI时再说 - Java系统属性,即
System.getProperties() - 操作系统环境变量
- 随机值属性源RandomValuePropertySource,会提供一些
random.*属性 - jar包外带profile的属性文件,即application-{profile}.properties/yml
- jar包内带profile的属性文件
- jar包外不带profile的属性文件,即application.properties/yml
- jar包内不带profile的属性文件
- 用@PropertySource和@Configuration标记的类
- 用SpringApplication.setDefaultProperties设置的默认属性
第12和14条jar包外的属性文件是指在jar包当前目录下的./config目录或./目录
有这么多的PropertySource,且严格按照上面的顺序排列,也就是说某个property定义的位置越靠前,优先级就越高。这样就可以实现一些很有用的效果,比如:
- 我写了一个第三方jar,而且配好了默认属性,就放在jar包内的application.properties中,你在引入这个jar包后,可以不改动jar包内的属性,而是通过设置命令行参数的方式进行修改
- 在单测的时候希望调整某些属性值,可以单独声明
@TestPropertySource类,这样只对单测生效,不影响正常配置
配置中心
为啥要有配置中心?
配置越来越多,服务器也越来越多,是不是要管起来?而且在改动配置的时候,需要能够快速发布到所有的机器上,并且希望有审批流、可以灰度发布、可以回滚。配置中心就是干这些事的。
比如携程的Apollo、阿里的Nacos、Spring自家的Spring Cloud Config。
那么配置中心要怎么和SpringBoot的配置管理能力结合起来用?聪明的朋友已经想到了,就是把配置中心上的配置注册成为一个PropertySource,且在设置优先级的时候设置到比较靠前的位置,这样配置中心的配置优先级就会比较高,可以优先生效。
相关信息
后面专门出一期文章聊一聊配置中心。对比一下各种配置中心的功能、选型、可用性。
怎么引用属性值
有两种比较优雅的引用方式:
第一种,在bean上声明@ConfigurationProperties,这个bean就可以通过依赖注入的方式被其他bean引用
@Component
@ConfigurationProperties(prefix = "baozi.verification-code")
@Data
public class VerificationCode {
// 对应baozi.verification-code.enable-send-sms这个属性
private boolean enableSendSms = false;
// 对应baozi.verification-code.expires-in-minutes
private int expiresInMinutes = 10;
}第二种,通过@Value引用
public class VerificationService {
// 引用环境变量用#号,支持在:后面设置默认值
@Value(value = "#{baozi.verification-code.enable-send-sms:false}")
private boolean enableSendSms;
// 引用系统变量用$号,支持在:后面设置默认值
@Value(value = "${baozi.verification-code.expires-in-minutes:10}")
private int expiresInMinutes;
}