Spring Boot 配置优先级这块,得拆成位置优先级 和格式优先级 两条线看,再加一条外部化配置源优先级(命令行、环境变量等凌驾于文件之上)。2.4 版本是个分水岭,加载逻辑改过,下面按最新(2.4+)讲,再标老版本差异。
一、位置优先级(同格式下,由高到低)
四个扫描位置,由外向内、由 config 向根:
| 优先级 | 位置 | 写法 | 说明 |
|---|---|---|---|
| 1(最高) | 项目根目录下 config/ |
file:./config/ |
jar 同目录的 config 子目录,运维最爱 |
| 2 | 项目根目录 | file:./ |
jar 同目录 |
| 3 | classpath 下 config/ |
classpath:/config/ |
resources/config/ |
| 4(最低) | classpath 根 | classpath:/ |
resources/ 下默认位置 |
规则 :高优先级覆盖低优先级的同名配置 ,不同名的互补加载。
举个例子,四个位置都有 server.port,最终生效的是 file:./config/application.yml 里的那个。
二、同目录下,不同格式的优先级(2.3 vs 2.4+ 有反转)
⚠️ 这里是高频踩坑点,很多人背的还是老答案。
- Spring Boot ≤ 2.3.x :
properties>yml>yaml(properties 最高) - Spring Boot ≥ 2.4.0 :
yaml>yml>properties(反过来,properties 最低)
2.4 引入 Config Data API 后不再以文件后缀定优先级,而是看 spring.config.import 声明的顺序;如果没显式 import,同目录 properties 和 yml 都解析,后加载的覆盖先加载的------实际表现就是 yml 翻过来压 properties 了。
三、外部化配置源优先级(凌驾于上面所有文件之上)
文件只是配置源之一,真正生产里改端口、改密码走的都是下面这些,由高到低:
- 命令行参数
java -jar app.jar --server.port=8081 - Java 系统属性
System.getProperties()(-D传的) - 操作系统环境变量
SERVER_PORT=8081 - JNDI
java:comp/env RandomValuePropertySourcerandom.*application-{profile}(jar 外)application-{profile}(jar 内)application(jar 外)application(jar 内)@PropertySource注解 (⚠️ 不支持 profile 变体,仅.properties)SpringApplication.setDefaultProperties()
口诀:命令行 > JVM 参数 > 环境变量 > jar 外 profile > jar 外默认 > jar 内 profile > jar 内默认。
四、Profile 文件的叠加规则
激活 dev 后,加载顺序是先默认、后 profile、同位置下 profile 压默认:
classpath:/application.yml (8080)
classpath:/config/application.yml (8082, 覆盖)
classpath:/application-dev.yml (8081)
classpath:/config/application-dev.yml (8083, 覆盖)
最终 server.port=8083。profile 文件永远压同名位置的默认文件,不管位置内外。
多 profile 同时激活时(--spring.profiles.active=prod,cloud),后声明覆盖先声明 ,即 application-cloud.yml 压 application-prod.yml。
五、Spring Cloud 的 bootstrap(特殊角色)
如果用 Spring Cloud(spring-cloud-starter-bootstrap),还有个 bootstrap.yml 会比所有 application.* 更早加载,用来连配置中心(nacos/config server),且不会被 application 覆盖。
Spring Cloud 2020+ 默认不启用 bootstrap,要走
spring.config.import=configserver:那套新路子。
六、2.4 另外两个值得知道的变更
spring.profiles→spring.config.activate.on-profile:profile 特定文档里不能再用来激活别的 profile 了- 不再自动合并 :2.3 前
application.yml+application-prod.yml隐式合并;2.4+ 如果application.yml里用了多文档---,是按文档顺序从前往后覆盖 ,不是按 profile 合并,需要spring.config.import显式引入外部文件,否则升级后容易出现"生产配置没加载"的灵异事件
一张总表收口
最高 ── 命令行 --server.port=8081
│
├─ JVM 参数 -Dserver.port=8081
├─ 环境变量 SERVER_PORT=8081
│
├─ bootstrap.yml (Spring Cloud, 仅引导期)
│
├─ file:./config/application-{profile}.yml
├─ file:./config/application.yml
├─ file:./application-{profile}.yml
├─ file:./application.yml
│
├─ classpath:/config/application-{profile}.yml
├─ classpath:/config/application.yml
├─ classpath:/application-{profile}.yml
└─ classpath:/application.yml
最低 ── @PropertySource / setDefaultProperties
实战建议 :本地 resources/application.yml 放默认值 + 多环境 application-{profile}.yml;生产 jar 外 ./config/application-prod.yml 放运维覆参(数据库、密钥),敏感信息优先走环境变量或 K8s Secret 挂载,别写死在文件里。