在 spring boot 中,配置文件不是“要么用这个,要么用那个”的单一选择,而是多个配置文件可以同时存在,并按优先级合并成最终的配置。这就是配置文件的合并机制。
一、合并的定义
配置文件合并是指 spring boot 在启动时,会从多个来源读取配置,将所有配置项汇总成一个统一的 propertysource 集合,形成一个完整的配置环境。当一个配置项在多个来源中出现时,根据优先级决定最终使用哪个值。
二、合并的参与方
spring boot 启动时,以下来源的配置会被合并:
- 命令行参数(最高优先级)
- 操作系统环境变量
- jvm 系统属性(
-d参数) application-{profile}.yml(profile 特定的配置)application.yml(默认配置)application-{profile}.properties(profile 特定的配置)application.properties(默认配置)@propertysource加载的自定义配置文件- 默认值(最低优先级)
三、合并规则
3.1 后加载覆盖先加载
高优先级的配置会覆盖低优先级的同名配置。同一优先级下,后加载的覆盖先加载的。
示例:
application.yml 配置了 server.port=8080,而 application-dev.yml 配置了 server.port=9090。当激活 dev profile 时,application-dev.yml 后加载,最终 server.port 的值是 9090。
3.2 同文件内的合并
yaml 多文档块(---)
同一个 yaml 文件中,--- 分隔的文档块会按顺序加载,后加载的覆盖前面的。
# 第一部分:默认配置
server:
port: 8080
---
# 第二部分:dev profile
spring:
config:
activate:
on-profile: dev
server:
port: 9090激活 dev 时,server.port 为 9090。
yaml 与 properties 共存
同一个键在 application.yml 和 application.properties 中都出现时,properties 优先级更高。propertiespropertysourceloader 和 yamlpropertysourceloader 的加载顺序决定了这个结果。
3.3 map/对象的合并
当同一个键在多个配置文件中都出现时,是“覆盖”还是“合并”?这取决于类型:
基本类型(string、number、boolean)
直接覆盖:后加载的值替换先加载的值。
对象类型
对象内的字段是逐层合并的,不是整体覆盖。
# application.yml
app:
name: myapp
features:
cache: true# application-dev.yml
app:
features:
logging: true合并后的结果是:
app:
name: myapp
features:
cache: true
logging: true
features 对象下的字段合并了,而不是整体覆盖。
列表/数组类型
列表的处理与对象不同。当两个配置文件中都有同一个列表键时,默认会整体替换,而不是追加元素。
# application.yml servers: - server1 - server2
# application-prod.yml servers: - prod-server1 - prod-server2
合并后 servers 的值为 [prod-server1, prod-server2],完全替换了默认值。如果希望追加,需要在代码层面处理。
3.4 属性来源的覆盖顺序
具体的覆盖顺序(从高到低):
- 命令行参数(
--server.port=8081) - 环境变量(
server_port=8081) - jvm 系统属性(
-dserver.port=8081) - 外部
application-{profile}.yml(config/目录下) - 外部
application.yml(config/目录下) - 内部
application-{profile}.yml(classpath 根目录) - 内部
application.yml(classpath 根目录) - 外部
application-{profile}.properties - 外部
application.properties - 内部
application-{profile}.properties - 内部
application.properties @propertysource自定义配置文件(按声明顺序,后声明的覆盖前面的)
四、profile 的合并逻辑
profile 是 spring boot 多环境配置的核心机制。当激活多个 profile 时,它们的配置会按顺序合并。
4.1 单个 profile
# application.yml server: port: 8080 # application-dev.yml server: port: 9090
激活 dev 时,server.port 为 9090。
4.2 多个 profile
当激活多个 profile 时,它们按照激活的顺序加载,后面加载的 profile 配置覆盖前面的。
# 激活 dev 和 prod --spring.profiles.active=dev,prod
加载顺序:application-dev.yml 先加载,application-prod.yml 后加载。后加载的覆盖先加载的。
五、实战示例
5.1 多环境配置合并
application.yml(默认配置):
app:
name: myapp
version: 1.0
features:
cache: true
logging: true
server:
port: 8080
application-dev.yml(开发环境):
app:
features:
logging: false
server:
port: 8081
application-prod.yml(生产环境):
app:
name: production-app
server:
port: 80
features:
cache: true
logging: false
激活 dev 时的合并结果:
app:
name: myapp
version: 1.0
features:
cache: true
logging: false # dev 覆盖
server:
port: 8081 # dev 覆盖
激活 prod 时的合并结果:
app:
name: production-app # prod 覆盖
version: 1.0
features:
cache: true
logging: false # prod 覆盖
server:
port: 80 # prod 覆盖
5.2 外部配置文件与内部配置文件合并
# 外部配置文件(优先级更高) /config/application.yml # 内部配置文件(classpath 根目录) application.yml
5.3 命令行覆盖配置
java -jar myapp.jar --app.name=cli-app
即使 application.yml 中配置了 app.name,命令行参数会覆盖它。
六、常见问题与排查
6.1 配置不生效
检查是否有高优先级的配置覆盖了你的配置。例如,环境变量、命令行参数、profile 特定配置文件。
在启动时开启 debug 模式:
debug: true
或启动参数:--debug,查看配置加载详情和自动配置报告。
6.2 配置被意外覆盖
使用 @configurationproperties 绑定到对象,通过日志打印配置值,确认最终生效的配置。
6.3 列表被替换而非追加
这是 yaml 合并的默认行为。如果希望追加,可以在代码中使用 spring 的 @configurationproperties 配合 @value 手动处理。
@configurationproperties(prefix = "servers")
public class serverproperties {
private list<string> list = new arraylist<>();
// getter/setter
}七、总结
| 配置来源 | 优先级 | 覆盖方式 |
|---|---|---|
| 命令行参数 | 最高 | 覆盖 |
| 环境变量 / jvm 系统属性 | 高 | 覆盖 |
| profile 特定配置 | 中高 | 覆盖默认配置 |
| 默认配置 | 最低 | 被覆盖 |
配置文件合并的规则可以概括为:高优先级覆盖低优先级,后加载覆盖先加载,对象类型合并字段,列表类型整体替换。
理解这些规则,就能准确预判最终生效的配置,避免因配置覆盖导致的意外行为。在排查配置问题时,查看 debug 模式下的配置加载日志是最有效的定位方式。
以上就是springboot将配置文件合并的方法详解的详细内容,更多关于springboot配置文件合并的资料请关注代码网其它相关文章!
发表评论