SpringCloud配置文件加载顺序与参数优先级详解
场景背景
在微服务架构中,配置管理变得更加复杂,特别是当使用Spring Cloud时。Spring Cloud引入了Bootstrap上下文的概念,用于在主应用上下文启动之前加载配置,这使得配置加载机制比单纯的Spring Boot更加复杂。本文通过实际运行和日志分析,深入解析Spring Cloud配置加载机制,帮助开发者掌握配置文件加载顺序和参数优先级。
⚠️ 本文基于 Spring Boot 2.7.0 和 Spring Cloud 2021.0.3(ConfigData 模型兼容层)进行实验验证。
从 Spring Cloud 2021.0 开始,Bootstrap 上下文默认禁用,若使用 ConfigData 模型,其功能由spring.config.import
替代。
本文通过添加spring-cloud-starter-bootstrap
人为启用旧模型,以便对比说明。
术语说明
在开始之前,我们先明确几个核心概念:
- Bootstrap上下文:Spring Cloud引入的用于加载外部配置(如配置中心)的独立上下文,在主应用上下文之前启动
- Application上下文:标准的Spring Boot应用上下文,用于加载本地配置文件
- 配置控制参数:用于控制配置加载行为的参数,如
--spring.profiles.active
、--spring.config.location
- 属性值参数:用于直接提供属性值的参数,如
--app.description="命令行参数"
、-Dapp.description="JVM系统属性"
配置加载机制概述
Spring Cloud配置加载分为两个阶段:
Bootstrap配置加载阶段
在Bootstrap阶段,Spring Cloud会加载所有以[bootstrap]为前缀的配置文件,用于初始化配置中心客户端等组件。
例如:当使用配置中心时,Bootstrap阶段会加载bootstrap.yml
配置文件以连接配置中心。
Application配置加载阶段
在Application阶段,Spring Boot加载所有以[application]为前缀的配置文件,这个阶段在Bootstrap阶段之后执行。
例如:当使用命令行参数--spring.profiles.active=prod
时,Spring Boot会在Application阶段确定需要加载application-prod.yml
配置文件。
一、Spring Cloud配置加载的双阶段机制
Spring Cloud配置加载严格分为两个串行阶段:
-
Bootstrap上下文阶段
- 加载所有bootstrap相关文件(包括profile-specific)
- 初始化配置中心客户端等组件
- 为Application阶段提供基础配置
-
Application上下文阶段
- 加载所有application相关文件
- 在Bootstrap上下文之后执行
- 合并Bootstrap阶段的配置
这两个阶段独立执行,不会交叉或并发执行。
二、外部配置属性源加载顺序
Spring Cloud使用特定的PropertySource顺序,旨在允许合理地覆盖值。属性按以下顺序加载(加载顺序从先到后):
- 默认属性(通过SpringApplication.setDefaultProperties指定)
- @PropertySource注解在@Configuration类上定义的属性
- Bootstrap配置数据文件(如bootstrap.properties等)
- Application配置数据文件(如application.properties等)
- RandomValuePropertySource,只包含random.*属性
- Java系统属性(System.getProperties())
- 操作系统环境变量
- 来自java:comp/env的JNDI属性
- ServletContext初始化参数
- ServletConfig初始化参数
- SPRING_APPLICATION_JSON中的属性(环境变量或系统属性中内嵌的JSON)
- 命令行参数
- 测试属性(@SpringBootTest#properties属性等)
三、配置文件加载顺序与优先级
在配置文件加载方面,Spring Boot和Spring Cloud遵循特定的搜索顺序和优先级规则。
配置文件搜索位置
Spring Boot按以下顺序搜索配置文件:
加载顺序 | 优先级 | 位置 | 类型 |
---|---|---|---|
1 | 最低 | classpath根目录 | 内部配置 |
2 | classpath下的/config包 | 内部配置 | |
3 | 当前目录 | 外部配置 | |
4 | 最高 | 当前目录下的/config子目录 | 外部配置 |
这意味着外部配置文件(位于jar包外部)优先级高于内部配置文件(位于jar包内部)。
同一目录下不同格式配置文件的处理
在同一目录下,Spring Boot会加载所有格式的配置文件(.properties、.yml、.yaml),但它们的加载顺序如下:
加载顺序 | 优先级 | 文件格式 | 说明 |
---|---|---|---|
1 | 最低 | .yaml | YAML格式,最先加载,优先级最低 |
2 | .yml | YAML格式,加载顺序居中,优先级中等 | |
3 | 最高 | .properties | Properties格式,最后加载,优先级最高 |
注意:同一目录下不同格式文件(.properties、.yml、.yaml)会按上述顺序加载,后加载的文件会覆盖前面的值。因此虽然加载顺序是.yaml > .yml > .properties,但优先级却是.properties > .yml > .yaml。
关键点
-
Bootstrap配置文件先于Application配置文件加载:Spring Cloud采用双阶段加载机制,Bootstrap上下文作为Application上下文的父上下文,会优先完成配置加载,然后才开始Application上下文的配置加载过程。
-
由
--spring.profiles.active
等参数控制加载内容:这些参数在Bootstrap阶段就被解析,用于确定需要加载的Profile特定配置文件,影响后续Application阶段的配置加载范围。 -
外部配置文件优先级高于jar包内配置文件:对于相同位置的配置文件,外部文件(如jar包同级目录)具有更高的优先级,会覆盖jar包内部的同名配置文件中的属性值。
-
同一目录下config目录优先于根目录:在相同优先级位置(如都是外部配置或都是内部配置),config子目录中的配置文件优先级高于根目录中的同名配置文件。
-
同一目录下不同格式配置文件加载顺序:.yaml > .yml > .properties(加载顺序),但覆盖优先级是.properties > .yml > .yaml:在同一目录下,Spring Boot会按顺序加载所有格式的配置文件,虽然.properties文件最后加载,但它的值会覆盖之前加载的.yml和.yaml文件中的同名属性,因此具有最高优先级。
四、实验设计与实现
实验环境搭建
- 创建Spring Boot + Spring Cloud项目
- 添加spring-cloud-starter-bootstrap依赖以启用Bootstrap上下文
- 在src/main/resources和外部目录下分别创建bootstrap和application配置文件
- 实现ConfigurationLoggingApplicationListener监听器,用于记录配置加载过程
实验文件:springcloud-demo.zip
实验一:验证默认加载顺序
java -Dfile.encoding=UTF-8 -jar demo.jar
配置加载顺序(按加载顺序从先到后):
1. bootstrap => app.description: null
2. systemProperties => app.description: null
3. systemEnvironment => app.description: null
4. random => app.description: null
5. cachedrandom => app.description: null
6. springCloudClientHostInfo => app.description: null
7. Config resource 'file [config\bootstrap.properties]' via location 'optional:file:./config/' => app.description: "外部config目录bootstrap.properties"
8. Config resource 'file [config\bootstrap.yml]' via location 'optional:file:./config/' => app.description: "外部config目录bootstrap.yml"
9. Config resource 'file [config\bootstrap.yaml]' via location 'optional:file:./config/' => app.description: "外部config目录bootstrap.yaml"
10. Config resource 'file [bootstrap.properties]' via location 'optional:file:./' => app.description: "外部根目录bootstrap.properties"
11. Config resource 'file [bootstrap.yml]' via location 'optional:file:./' => app.description: "外部根目录bootstrap.yml"
12. Config resource 'file [bootstrap.yaml]' via location 'optional:file:./' => app.description: "外部根目录bootstrap.yaml"
13. Config resource 'class path resource [config/bootstrap.properties]' via location 'optional:classpath:/config/' => app.description: "jar包内config/bootstrap.properties"
14. Config resource 'class path resource [config/bootstrap.yml]' via location 'optional:classpath:/config/' => app.description: "jar包内config/bootstrap.yml"
15. Config resource 'class path resource [config/bootstrap.yaml]' via location 'optional:classpath:/config/' => app.description: "jar包内config/bootstrap.yaml"
16. Config resource 'class path resource [bootstrap.properties]' via location 'optional:classpath:/' => app.description: "jar包内根目录bootstrap.properties"
17. Config resource 'class path resource [bootstrap.yml]' via location 'optional:classpath:/' => app.description: "jar包内根目录bootstrap.yml"
18. Config resource 'class path resource [bootstrap.yaml]' via location 'optional:classpath:/' => app.description: "jar包内根目录bootstrap.yaml"
最终生效的配置值:
app.description: 外部config目录bootstrap.properties
app.summary: null
接着是Application阶段的加载:
1. servletConfigInitParams => app.description: null
2. servletContextInitParams => app.description: null
3. systemProperties => app.description: null
4. systemEnvironment => app.description: null
5. random => app.description: null
6. springCloudDefaultProperties => app.description: "外部config目录bootstrap.properties"
7. cachedrandom => app.description: null
8. springCloudClientHostInfo => app.description: null
9. Config resource 'file [config\application.properties]' via location 'optional:file:./config/' => app.description: "外部config目录application.properties"
=> app.summary: "这是外部config目录的application.properties配置文件"
10. Config resource 'file [config\application.yml]' via location 'optional:file:./config/' => app.description: "外部config目录application.yml"
=> app.summary: "这是外部config目录的application.yml配置文件"
11. Config resource 'file [config\application.yaml]' via location 'optional:file:./config/' => app.description: "外部config目录application.yaml"
=> app.summary: "这是外部config目录的application.yaml配置文件"
12. Config resource 'file [application.properties]' via location 'optional:file:./' => app.description: "外部根目录application.properties"
=> app.summary: "这是外部根目录的application.properties配置文件"
13. Config resource 'file [application.yml]' via location 'optional:file:./' => app.description: "外部根目录application.yml"
=> app.summary: "这是外部根目录的application.yml配置文件"
14. Config resource 'file [application.yaml]' via location 'optional:file:./' => app.description: "外部根目录application.yaml"
=> app.summary: "这是外部根目录的application.yaml配置文件"
15. Config resource 'class path resource [config/application.properties]' via location 'optional:classpath:/config/' => app.description: "jar包内config/application.properties"
=> app.summary: "这是jar包内config目录的application.properties配置文件"
16. Config resource 'class path resource [config/application.yml]' via location 'optional:classpath:/config/' => app.description: "jar包内config/application.yml"
=> app.summary: "这是jar包内config目录的application.yml配置文件"
17. Config resource 'class path resource [config/application.yaml]' via location 'optional:classpath:/config/' => app.description: "jar包内config/application.yaml"
=> app.summary: "这是jar包内config目录的application.yaml配置文件"
18. Config resource 'class path resource [application.properties]' via location 'optional:classpath:/' => app.description: "jar包内根目录application.properties"
=> app.summary: "这是jar包内根目录的application.properties配置文件"
19. Config resource 'class path resource [application.yml]' via location 'optional:classpath:/' => app.description: "jar包内根目录application.yml"
=> app.summary: "这是jar包内根目录的application.yml配置文件"
20. Config resource 'class path resource [application.yaml]' via location 'optional:classpath:/' => app.description: "jar包内根目录application.yaml"
=> app.summary: "这是jar包内根目录的application.yaml配置文件"
最终生效的配置值:
app.description: 外部config目录bootstrap.properties
app.summary: 这是外部config目录的application.properties配置文件
结论:
- Bootstrap配置文件先于Application配置文件加载
- jar包内的配置文件先被加载,但外部配置文件具有更高的优先级
- 同级目录下config目录优先于根目录
- 最终生效的是外部config目录的bootstrap.properties(注意:Bootstrap阶段加载的配置会传递给Application阶段)
实验二:验证 Profile 特定加载
java -Dfile.encoding=UTF-8 -jar demo.jar --spring.profiles.active=prod
配置加载顺序(按加载顺序从先到后):
1. bootstrap => app.description: null
2. commandLineArgs => app.description: null
3. systemProperties => app.description: null
4. systemEnvironment => app.description: null
5. random => app.description: null
6. cachedrandom => app.description: null
7. springCloudClientHostInfo => app.description: null
8. Config resource 'file [config\bootstrap-prod.properties]' via location 'optional:file:./config/' => app.description: "外部config目录bootstrap-prod.properties"
9. Config resource 'file [config\bootstrap-prod.yml]' via location 'optional:file:./config/' => app.description: "外部config目录bootstrap-prod.yml"
10. Config resource 'file [config\bootstrap-prod.yaml]' via location 'optional:file:./config/' => app.description: "外部config目录bootstrap-prod.yaml"
11. Config resource 'file [bootstrap-prod.properties]' via location 'optional:file:./' => app.description: "外部根目录bootstrap-prod.properties"
12. Config resource 'file [bootstrap-prod.yml]' via location 'optional:file:./' => app.description: "外部根目录bootstrap-prod.yml"
13. Config resource 'file [bootstrap-prod.yaml]' via location 'optional:file:./' => app.description: "外部根目录bootstrap-prod.yaml"
14. Config resource 'file [config\bootstrap.properties]' via location 'optional:file:./config/' => app.description: "外部config目录bootstrap.properties"
15. Config resource 'file [config\bootstrap.yml]' via location 'optional:file:./config/' => app.description: "外部config目录bootstrap.yml"
16. Config resource 'file [config\bootstrap.yaml]' via location 'optional:file:./config/' => app.description: "外部config目录bootstrap.yaml"
17. Config resource 'file [bootstrap.properties]' via location 'optional:file:./' => app.description: "外部根目录bootstrap.properties"
18. Config resource 'file [bootstrap.yml]' via location 'optional:file:./' => app.description: "外部根目录bootstrap.yml"
19. Config resource 'file [bootstrap.yaml]' via location 'optional:file:./' => app.description: "外部根目录bootstrap.yaml"
20. Config resource 'class path resource [config/bootstrap-prod.properties]' via location 'optional:classpath:/config/' => app.description: "jar包内config/bootstrap-prod.properties"
21. Config resource 'class path resource [config/bootstrap-prod.yml]' via location 'optional:classpath:/config/' => app.description: "jar包内config/bootstrap-prod.yml"
22. Config resource 'class path resource [config/bootstrap-prod.yaml]' via location 'optional:classpath:/config/' => app.description: "jar包内config/bootstrap-prod.yaml"
23. Config resource 'class path resource [bootstrap-prod.properties]' via location 'optional:classpath:/' => app.description: "jar包内根目录bootstrap-prod.properties"
24. Config resource 'class path resource [bootstrap-prod.yml]' via location 'optional:classpath:/' => app.description: "jar包内根目录bootstrap-prod.yml"
25. Config resource 'class path resource [bootstrap-prod.yaml]' via location 'optional:classpath:/' => app.description: "jar包内根目录bootstrap-prod.yaml"
26. Config resource 'class path resource [config/bootstrap.properties]' via location 'optional:classpath:/config/' => app.description: "jar包内config/bootstrap.properties"
27. Config resource 'class path resource [config/bootstrap.yml]' via location 'optional:classpath:/config/' => app.description: "jar包内config/bootstrap.yml"
28. Config resource 'class path resource [config/bootstrap.yaml]' via location 'optional:classpath:/config/' => app.description: "jar包内config/bootstrap.yaml"
29. Config resource 'class path resource [bootstrap.properties]' via location 'optional:classpath:/' => app.description: "jar包内根目录bootstrap.properties"
30. Config resource 'class path resource [bootstrap.yml]' via location 'optional:classpath:/' => app.description: "jar包内根目录bootstrap.yml"
31. Config resource 'class path resource [bootstrap.yaml]' via location 'optional:classpath:/' => app.description: "jar包内根目录bootstrap.yaml"
最终生效的配置值:
app.description: 外部config目录bootstrap-prod.properties
app.summary: null
Application阶段加载:
1. commandLineArgs => app.description: null
2. servletConfigInitParams => app.description: null
3. servletContextInitParams => app.description: null
4. systemProperties => app.description: null
5. systemEnvironment => app.description: null
6. random => app.description: null
7. springCloudDefaultProperties => app.description: "外部config目录bootstrap-prod.properties"
8. cachedrandom => app.description: null
9. springCloudClientHostInfo => app.description: null
10. Config resource 'file [config\application-prod.properties]' via location 'optional:file:./config/' => app.description: "外部config目录application-prod.properties"
=> app.summary: "这是外部config目录的application-prod.properties配置文件"
11. Config resource 'file [config\application-prod.yml]' via location 'optional:file:./config/' => app.description: "外部config目录application-prod.yml"
=> app.summary: "这是外部config目录的application-prod.yml配置文件"
12. Config resource 'file [config\application-prod.yaml]' via location 'optional:file:./config/' => app.description: "外部config目录application-prod.yaml"
=> app.summary: "这是外部config目录的application-prod.yaml配置文件"
13. Config resource 'file [application-prod.properties]' via location 'optional:file:./' => app.description: "外部根目录application-prod.properties"
=> app.summary: "这是外部根目录的application-prod.properties配置文件"
14. Config resource 'file [application-prod.yml]' via location 'optional:file:./' => app.description: "外部根目录application-prod.yml"
=> app.summary: "这是外部根目录的application-prod.yml配置文件"
15. Config resource 'file [application-prod.yaml]' via location 'optional:file:./' => app.description: "外部根目录application-prod.yaml"
=> app.summary: "这是外部根目录的application-prod.yaml配置文件"
16. Config resource 'file [config\application.properties]' via location 'optional:file:./config/' => app.description: "外部config目录application.properties"
=> app.summary: "这是外部config目录的application.properties配置文件"
17. Config resource 'file [config\application.yml]' via location 'optional:file:./config/' => app.description: "外部config目录application.yml"
=> app.summary: "这是外部config目录的application.yml配置文件"
18. Config resource 'file [config\application.yaml]' via location 'optional:file:./config/' => app.description: "外部config目录application.yaml"
=> app.summary: "这是外部config目录的application.yaml配置文件"
19. Config resource 'file [application.properties]' via location 'optional:file:./' => app.description: "外部根目录application.properties"
=> app.summary: "这是外部根目录的application.properties配置文件"
20. Config resource 'file [application.yml]' via location 'optional:file:./' => app.description: "外部根目录application.yml"
=> app.summary: "这是外部根目录的application.yml配置文件"
21. Config resource 'file [application.yaml]' via location 'optional:file:./' => app.description: "外部根目录application.yaml"
=> app.summary: "这是外部根目录的application.yaml配置文件"
22. Config resource 'class path resource [config/application-prod.properties]' via location 'optional:classpath:/config/' => app.description: "jar包内config/application-prod.properties"
=> app.summary: "这是jar包内config目录的application-prod.properties配置文件"
23. Config resource 'class path resource [config/application-prod.yml]' via location 'optional:classpath:/config/' => app.description: "jar包内config/application-prod.yml"
=> app.summary: "这是jar包内config目录的application-prod.yml配置文件"
24. Config resource 'class path resource [config/application-prod.yaml]' via location 'optional:classpath:/config/' => app.description: "jar包内config/application-prod.yaml"
=> app.summary: "这是jar包内config目录的application-prod.yaml配置文件"
25. Config resource 'class path resource [application-prod.properties]' via location 'optional:classpath:/' => app.description: "jar包内根目录application-prod.properties"
=> app.summary: "这是jar包内根目录的application-prod.properties配置文件"
26. Config resource 'class path resource [application-prod.yml]' via location 'optional:classpath:/' => app.description: "jar包内根目录application-prod.yml"
=> app.summary: "这是jar包内根目录的application-prod.yml配置文件"
27. Config resource 'class path resource [application-prod.yaml]' via location 'optional:classpath:/' => app.description: "jar包内根目录application-prod.yaml"
=> app.summary: "这是jar包内根目录的application-prod.yaml配置文件"
28. Config resource 'class path resource [config/application.properties]' via location 'optional:classpath:/config/' => app.description: "jar包内config/application.properties"
=> app.summary: "这是jar包内config目录的application.properties配置文件"
29. Config resource 'class path resource [config/application.yml]' via location 'optional:classpath:/config/' => app.description: "jar包内config/application.yml"
=> app.summary: "这是jar包内config目录的application.yml配置文件"
30. Config resource 'class path resource [config/application.yaml]' via location 'optional:classpath:/config/' => app.description: "jar包内config/application.yaml"
=> app.summary: "这是jar包内config目录的application.yaml配置文件"
31. Config resource 'class path resource [application.properties]' via location 'optional:classpath:/' => app.description: "jar包内根目录application.properties"
=> app.summary: "这是jar包内根目录的application.properties配置文件"
32. Config resource 'class path resource [application.yml]' via location 'optional:classpath:/' => app.description: "jar包内根目录application.yml"
=> app.summary: "这是jar包内根目录的application.yml配置文件"
33. Config resource 'class path resource [application.yaml]' via location 'optional:classpath:/' => app.description: "jar包内根目录application.yaml"
=> app.summary: "这是jar包内根目录的application.yaml配置文件"
最终生效的配置值:
app.description: 外部config目录bootstrap-prod.properties
app.summary: 这是外部config目录的application-prod.properties配置文件
结论:
- Bootstrap配置文件先于Application配置文件加载
--spring.profiles.active=prod
会触发加载所有位置的*-prod.*
配置文件- jar包内的配置文件先被加载,但外部配置文件具有更高的优先级
- 同级目录下config目录优先于根目录
- 最终生效的是外部config目录的bootstrap-prod.properties
五、属性值参数加载顺序验证
实验三:命令行 vs JVM 参数 vs 环境变量
java -Dfile.encoding=UTF-8 -jar demo.jar --spring.profiles.active=prod --app.description="命令行参数配置"
配置加载顺序(按加载顺序从先到后):
1. bootstrap => app.description: null
2. commandLineArgs => app.description: "命令行参数配置"
3. systemProperties => app.description: null
4. systemEnvironment => app.description: null
5. random => app.description: null
6. cachedrandom => app.description: null
7. springCloudClientHostInfo => app.description: null
8. Config resource 'file [config\bootstrap-prod.properties]' via location 'optional:file:./config/' => app.description: "外部config目录bootstrap-prod.properties"
9. Config resource 'file [config\bootstrap-prod.yml]' via location 'optional:file:./config/' => app.description: "外部config目录bootstrap-prod.yml"
10. Config resource 'file [config\bootstrap-prod.yaml]' via location 'optional:file:./config/' => app.description: "外部config目录bootstrap-prod.yaml"
11. Config resource 'file [bootstrap-prod.properties]' via location 'optional:file:./' => app.description: "外部根目录bootstrap-prod.properties"
12. Config resource 'file [bootstrap-prod.yml]' via location 'optional:file:./' => app.description: "外部根目录bootstrap-prod.yml"
13. Config resource 'file [bootstrap-prod.yaml]' via location 'optional:file:./' => app.description: "外部根目录bootstrap-prod.yaml"
14. Config resource 'file [config\bootstrap.properties]' via location 'optional:file:./config/' => app.description: "外部config目录bootstrap.properties"
15. Config resource 'file [config\bootstrap.yml]' via location 'optional:file:./config/' => app.description: "外部config目录bootstrap.yml"
16. Config resource 'file [config\bootstrap.yaml]' via location 'optional:file:./config/' => app.description: "外部config目录bootstrap.yaml"
17. Config resource 'file [bootstrap.properties]' via location 'optional:file:./' => app.description: "外部根目录bootstrap.properties"
18. Config resource 'file [bootstrap.yml]' via location 'optional:file:./' => app.description: "外部根目录bootstrap.yml"
19. Config resource 'file [bootstrap.yaml]' via location 'optional:file:./' => app.description: "外部根目录bootstrap.yaml"
20. Config resource 'class path resource [config/bootstrap-prod.properties]' via location 'optional:classpath:/config/' => app.description: "jar包内config/bootstrap-prod.properties"
21. Config resource 'class path resource [config/bootstrap-prod.yml]' via location 'optional:classpath:/config/' => app.description: "jar包内config/bootstrap-prod.yml"
22. Config resource 'class path resource [config/bootstrap-prod.yaml]' via location 'optional:classpath:/config/' => app.description: "jar包内config/bootstrap-prod.yaml"
23. Config resource 'class path resource [bootstrap-prod.properties]' via location 'optional:classpath:/' => app.description: "jar包内根目录bootstrap-prod.properties"
24. Config resource 'class path resource [bootstrap-prod.yml]' via location 'optional:classpath:/' => app.description: "jar包内根目录bootstrap-prod.yml"
25. Config resource 'class path resource [bootstrap-prod.yaml]' via location 'optional:classpath:/' => app.description: "jar包内根目录bootstrap-prod.yaml"
26. Config resource 'class path resource [config/bootstrap.properties]' via location 'optional:classpath:/config/' => app.description: "jar包内config/bootstrap.properties"
27. Config resource 'class path resource [config/bootstrap.yml]' via location 'optional:classpath:/config/' => app.description: "jar包内config/bootstrap.yml"
28. Config resource 'class path resource [config/bootstrap.yaml]' via location 'optional:classpath:/config/' => app.description: "jar包内config/bootstrap.yaml"
29. Config resource 'class path resource [bootstrap.properties]' via location 'optional:classpath:/' => app.description: "jar包内根目录bootstrap.properties"
30. Config resource 'class path resource [bootstrap.yml]' via location 'optional:classpath:/' => app.description: "jar包内根目录bootstrap.yml"
31. Config resource 'class path resource [bootstrap.yaml]' via location 'optional:classpath:/' => app.description: "jar包内根目录bootstrap.yaml"
最终生效的配置值:
app.description: 命令行参数配置
app.summary: null
Application阶段加载:
1. commandLineArgs => app.description: "命令行参数配置"
2. servletConfigInitParams => app.description: null
3. servletContextInitParams => app.description: null
4. systemProperties => app.description: null
5. systemEnvironment => app.description: null
6. random => app.description: null
7. springCloudDefaultProperties => app.description: "外部config目录bootstrap-prod.properties"
8. cachedrandom => app.description: null
9. springCloudClientHostInfo => app.description: null
10. Config resource 'file [config\application-prod.properties]' via location 'optional:file:./config/' => app.description: "外部config目录application-prod.properties"
=> app.summary: "这是外部config目录的application-prod.properties配置文件"
11. Config resource 'file [config\application-prod.yml]' via location 'optional:file:./config/' => app.description: "外部config目录application-prod.yml"
=> app.summary: "这是外部config目录的application-prod.yml配置文件"
12. Config resource 'file [config\application-prod.yaml]' via location 'optional:file:./config/' => app.description: "外部config目录application-prod.yaml"
=> app.summary: "这是外部config目录的application-prod.yaml配置文件"
13. Config resource 'file [application-prod.properties]' via location 'optional:file:./' => app.description: "外部根目录application-prod.properties"
=> app.summary: "这是外部根目录的application-prod.properties配置文件"
14. Config resource 'file [application-prod.yml]' via location 'optional:file:./' => app.description: "外部根目录application-prod.yml"
=> app.summary: "这是外部根目录的application-prod.yml配置文件"
15. Config resource 'file [application-prod.yaml]' via location 'optional:file:./' => app.description: "外部根目录application-prod.yaml"
=> app.summary: "这是外部根目录的application-prod.yaml配置文件"
16. Config resource 'file [config\application.properties]' via location 'optional:file:./config/' => app.description: "外部config目录application.properties"
=> app.summary: "这是外部config目录的application.properties配置文件"
17. Config resource 'file [config\application.yml]' via location 'optional:file:./config/' => app.description: "外部config目录application.yml"
=> app.summary: "这是外部config目录的application.yml配置文件"
18. Config resource 'file [config\application.yaml]' via location 'optional:file:./config/' => app.description: "外部config目录application.yaml"
=> app.summary: "这是外部config目录的application.yaml配置文件"
19. Config resource 'file [application.properties]' via location 'optional:file:./' => app.description: "外部根目录application.properties"
=> app.summary: "这是外部根目录的application.properties配置文件"
20. Config resource 'file [application.yml]' via location 'optional:file:./' => app.description: "外部根目录application.yml"
=> app.summary: "这是外部根目录的application.yml配置文件"
21. Config resource 'file [application.yaml]' via location 'optional:file:./' => app.description: "外部根目录application.yaml"
=> app.summary: "这是外部根目录的application.yaml配置文件"
22. Config resource 'class path resource [config/application-prod.properties]' via location 'optional:classpath:/config/' => app.description: "jar包内config/application-prod.properties"
=> app.summary: "这是jar包内config目录的application-prod.properties配置文件"
23. Config resource 'class path resource [config/application-prod.yml]' via location 'optional:classpath:/config/' => app.description: "jar包内config/application-prod.yml"
=> app.summary: "这是jar包内config目录的application-prod.yml配置文件"
24. Config resource 'class path resource [config/application-prod.yaml]' via location 'optional:classpath:/config/' => app.description: "jar包内config/application-prod.yaml"
=> app.summary: "这是jar包内config目录的application-prod.yaml配置文件"
25. Config resource 'class path resource [application-prod.properties]' via location 'optional:classpath:/' => app.description: "jar包内根目录application-prod.properties"
=> app.summary: "这是jar包内根目录的application-prod.properties配置文件"
26. Config resource 'class path resource [application-prod.yml]' via location 'optional:classpath:/' => app.description: "jar包内根目录application-prod.yml"
=> app.summary: "这是jar包内根目录的application-prod.yml配置文件"
27. Config resource 'class path resource [application-prod.yaml]' via location 'optional:classpath:/' => app.description: "jar包内根目录application-prod.yaml"
=> app.summary: "这是jar包内根目录的application-prod.yaml配置文件"
28. Config resource 'class path resource [config/application.properties]' via location 'optional:classpath:/config/' => app.description: "jar包内config/application.properties"
=> app.summary: "这是jar包内config目录的application.properties配置文件"
29. Config resource 'class path resource [config/application.yml]' via location 'optional:classpath:/config/' => app.description: "jar包内config/application.yml"
=> app.summary: "这是jar包内config目录的application.yml配置文件"
30. Config resource 'class path resource [config/application.yaml]' via location 'optional:classpath:/config/' => app.description: "jar包内config/application.yaml"
=> app.summary: "这是jar包内config目录的application.yaml配置文件"
31. Config resource 'class path resource [application.properties]' via location 'optional:classpath:/' => app.description: "jar包内根目录application.properties"
=> app.summary: "这是jar包内根目录的application.properties配置文件"
32. Config resource 'class path resource [application.yml]' via location 'optional:classpath:/' => app.description: "jar包内根目录application.yml"
=> app.summary: "这是jar包内根目录的application.yml配置文件"
33. Config resource 'class path resource [application.yaml]' via location 'optional:classpath:/' => app.description: "jar包内根目录application.yaml"
=> app.summary: "这是jar包内根目录的application.yaml配置文件"
最终生效的配置值:
app.description: 命令行参数配置
app.summary: 这是外部config目录的application-prod.properties配置文件
结论:命令行参数 > JVM系统属性(-D参数) > 环境变量,符合官方文档定义的优先级顺序。
六、配置加载机制深入解析
Bootstrap与Application双阶段加载机制
在Spring Cloud中,配置加载严格分为两个串行阶段:
-
Bootstrap上下文阶段
- 加载所有bootstrap相关文件(包括profile-specific)
- 初始化配置中心客户端等组件
- 为Application阶段提供基础配置
-
Application上下文阶段
- 加载所有application相关文件
- 在Bootstrap上下文之后执行
- 合并Bootstrap阶段的配置
这两个阶段独立执行,不会交叉或并发执行。
为什么Bootstrap配置优先级高于Application配置?
这是很多开发者容易困惑的问题。虽然Bootstrap配置先被加载,Application配置后被加载,但最终Bootstrap配置的值却生效了。这是为什么呢?
关键在于理解Spring Cloud的设计理念:
-
Bootstrap上下文是Application上下文的父上下文
- Bootstrap上下文先创建并加载配置
- Application上下文后创建,但它继承了Bootstrap上下文的所有配置
- 这种父子关系使得Bootstrap配置成为Application配置的"默认值"
-
属性源加载顺序机制
- Spring将所有配置源按照加载顺序排序,形成一个PropertySource列表
- Bootstrap相关的配置源在排序中位置较高,具有更高的优先级
- 即使Application配置后加载,它在优先级排序中仍然低于Bootstrap配置
-
设计目的
- Bootstrap配置通常包含连接配置中心、加密解密等关键基础设施配置
- 这些配置需要在Application上下文初始化之前就可用
- 保证关键配置不会被普通的Application配置意外覆盖
文件加载顺序与覆盖机制
在Spring Cloud中,配置文件的加载遵循"后加载覆盖先加载"的原则。这意味着:
- 同一属性在多个配置文件中定义时,后加载的文件中的值会覆盖先加载的文件中的值
- 加载顺序按照优先级从低到高进行,优先级高的位置的文件会后加载
例如,在默认配置下:
- 首先加载
classpath:/bootstrap.yaml
(Bootstrap阶段,优先级较低) - 然后加载
classpath:/bootstrap.yml
- 接着加载
classpath:/bootstrap.properties
- 然后加载
classpath:/config/bootstrap.yaml
- 依此类推,最后加载
file:./config/bootstrap.properties
(Bootstrap阶段,优先级最高) - 接着开始Application阶段,加载
classpath:/application.yaml
- 依此类推,最后加载
file:./config/application.properties
(Application阶段,优先级最高)
如果app.description
在所有这些文件中都有定义,最终生效的将是file:./config/application.properties
中的值。但在我们的实验中,Bootstrap配置的优先级更高,所以最终值来自Bootstrap配置。
七、实践应用总结
场景 | 推荐做法 |
---|---|
外部配置中心接入 | 使用bootstrap配置文件配置配置中心连接信息 |
多环境配置 | 使用 --spring.profiles.active 切换 |
容器部署 | 通过 --spring.config.location 或挂载 /config |
敏感配置 | 使用环境变量或命令行参数注入 |
八、核心原则总结
- Bootstrap配置优于Application配置
- 命令行参数最高优先级
- ⚠️ 外部配置优于内部配置
- 特定环境配置覆盖通用配置
- 同级目录下 config 优先
- 后加载覆盖先加载
- ⚠️ 加载与解析分离:Bootstrap和Application两个阶段
- 同一目录下配置文件格式加载顺序:
.properties > .yml > .yaml
(实现细节)
九、版本注意事项
Spring Boot 2.4+ 和 Spring Cloud 2020.x+ 采用全新的 ConfigData 加载机制,
原则一致但底层实现差异较大,建议阅读对应版本文档。
Bootstrap上下文在新版本中默认不启用,需要添加spring-cloud-starter-bootstrap依赖。
评论区