在 Spring Boot 项目的部署运维中(尤其是使用 java -jar 启动时),配置文件的加载逻辑常常让人感到困惑:
"如果我在 jar 包旁边放了配置文件,config 目录下也放了一个,jar 包里还有一个,到底谁生效?" "外部配置文件是会把内部的完全替换掉吗?"
今天我们就通过一篇文章,彻底讲透 Spring Boot 配置文件的 "优先级覆盖" 与 "互补合并" 两大核心机制。
一、 核心机制图解
首先,我们要建立一个概念:Spring Boot 读取配置,不是"非黑即白"的文件替换,而是类似"千层饼"或"PS图层"的叠加。
它遵循两个原则:
- 优先级(Priority): 决定谁说了算(遇到冲突,听高优先级的)。
- 互补合并(Merge): 决定如何共存(没冲突的,大家一起生效)。
二、 优先级梯队(谁是老大?)
当程序启动时,Spring Boot 会按照以下顺序扫描配置文件,优先级从高到低:
- 命令行参数
(最高)java -jar app.jar --server.port=9999- 说明: 一票否决权,通常用于临时救急。
- 运行目录下的 config 子目录
file:./config/application.yml- 说明: 外部配置的王者,优先级高于根目录。
- 运行目录(Jar 包同级目录)
file:./application.yml- 说明: 最常用的生产环境配置位置。
- Classpath 内部
(最低/保底)classpath:/application.yml- 说明: 打包在 Jar 包里的默认配置(开发时写的)。
三、 互补合并机制(如何共存?)
这是很多新手容易误解的地方。
外部配置文件生效,并不代表内部配置文件"失效"或"被丢弃"! Spring Boot 会把所有扫描到的配置文件加载进内存进行合并。
我们可以把它想象成 Photoshop 的图层叠加:
- 高优先级的配置在上层。
- 低优先级的配置在下层。
- 如果上层没有设置某个值(透明),就会透过上层看到下层的值。
叠加规则的三大定律:
- 冲突覆盖(Override): Key 相同,高优先级覆盖低优先级。
- 缺省保留(Retain): Key 仅在低优先级存在,会被保留。
- 增量追加(Add): Key 仅在高优先级存在,会被追加。
四、 终极实战演练
为了彻底看懂,我们假设有三个配置文件同时存在:
1. 层级最低:Jar 包内部 (classpath)
这是开发时的全量配置:
yaml
server:
port: 8080 # 默认端口
spring:
application:
name: my-app # 应用名
datasource:
url: jdbc:mysql://localhost/dev_db # 开发库
2. 层级中等:Jar 包同级目录 (./application.yml)
运维部署时放的:
yaml
server:
port: 9000 # 【冲突】想改成 9000
spring:
datasource:
url: jdbc:mysql://192.168.1.1/prod_db # 【冲突】改成生产库
3. 层级最高:Config 子目录 (./config/application.yml)
为了特殊调试,又加了一个:
yaml
server:
port: 9999 # 【冲突】这里级别最高!
logging:
level: debug # 【新增】这里独有的配置
💥 最终合并结果(程序实际运行配置)
当运行 java -jar app.jar 时,最终生效的配置如下:
| 配置项 (Key) | 最终值 | 来源与原因 |
|---|---|---|
server.port |
9999 | config目录 (最高优) 覆盖了 jar包旁 和 jar包内 的配置。 |
spring.datasource.url |
.../prod_db | jar包旁目录 (中优) 覆盖了 jar包内 的配置,config目录没写,所以"透"下来了。 |
spring.application.name |
my-app | jar包内部 (保底)。外部两个文件都没写这个配置,沿用默认值。 |
logging.level |
debug | config目录 (新增)。这是一个全新的配置,被合并进来了。 |
五、 总结与最佳实践
- 不要试图在外部重写所有配置 :利用"互补合并"特性,外部配置文件(
application.yml)应该只包含需要修改的差异化配置(如数据库密码、端口、IP)。让那些通用的配置(如 Jackson 格式化、线程池默认设置)留在 Jar 包里作为保底。 - 目录结构建议 :
- 如果是简单的单机部署,直接把
application.yml放在 Jar 包旁边即可。 - 如果你希望目录更整洁,或者有多个辅助配置文件,建议创建一个
config文件夹存放。
- 如果是简单的单机部署,直接把