Spring Boot 配置文件加载顺序
阿里P6面试间,候选人小孙在面试中被问到:
"application.yml 和 application-dev.yml 的加载顺序是什么?哪个优先级更高?"
小孙说:"dev 会覆盖主配置吧?因为它专门给开发环境用的。"面试官追问:"那如果两个文件都定义了 server.port,以哪个为准?"
小孙说:"dev 的吧?"面试官拿起笔:"那我换个问法:jar 包外的 application-dev.yml 和 jar 包内的 application.yml,哪个优先级高?"
小孙停顿了三秒,说:"应该是 jar 包外的?"
面试官说:"回答反了。"
【面试官心理】
这道题我用来测试候选人对 Spring Boot 配置体系的最基本理解。99% 的候选人不能完整说出加载顺序,能答对 jar 包内外优先级的只有 5%。这道题太细节了,大多数人只在 IDE 里改过配置,从没深入研究过官方文档。
一、配置文件加载顺序(完整版) 🔴
1.1 Spring Boot 2.x 的加载顺序
Spring Boot 的配置文件加载遵循后面的覆盖前面的原则。以下是完整的加载顺序,从低到高:
重点:jar 包内的配置文件优先级比 jar 包外的低!这是很多人答反的点。不是 dev.yml 覆盖主配置,而是加载位置决定了优先级——jar 包外的配置比 jar 包内的高。
1.2 面试必考的口诀
记住这个优先级口诀:命令行 > jar外config目录 > jar外根目录 > jar内
1.3 properties vs yml 优先级
当 properties 和 yml 文件同时存在时,properties 的优先级高于 yml:
这个规则在 Spring Boot 2.4 之后有变化。Spring Boot 2.4 引入了 spring.config.activate.on-profile 替代了之前基于文件命名的 profile 激活方式。新旧两种方式在 2.4+ 中是并存的,但 3.x 完全移除了旧方式。
二、Profile 激活顺序 🟡
2.1 激活 profile 的多种方式
2.2 多 Profile 文件的加载逻辑
加载逻辑:
- 先加载主文件
application.yml - 根据
spring.profiles.active加载对应的 profile 文件 - profile 文件中的属性覆盖主文件中的同名属性
📖 点击展开加载优先级图
三、@PropertySource 不加载 yml 🟡
3.1 @PropertySource 的局限性
@PropertySource 是 Spring 提供的注解,用于加载额外的 properties 文件:
但是!@PropertySource 不支持加载 yml/yaml 文件:
如果非要加载自定义的 yml 文件,需要使用 PropertySourcesPlaceholderConfigurer 或者 YamlPropertiesFactoryBean:
Spring Boot 2.4+ 建议使用 @ConfigurationProperties 绑定 yml 配置,而不是使用 @PropertySource。如果一定要加载自定义 yml 文件,需要自定义 Bean 配置,比较麻烦。
四、random.* 属性源 🟢
4.1 使用随机值的场景
Spring Boot 会自动注册一个 RandomValuePropertySource,它的优先级仅次于命令行参数:
五、❌ 错误示范
5.1 认为 dev.yml 一定覆盖主配置
候选人原话:"application-dev.yml 会覆盖 application.yml,因为 profile 就是用来区分环境的。"
问题诊断:
- 忽略了加载位置对优先级的影响
- jar 包内的 dev.yml 不一定比 jar 包内的主配置优先级高
- 把"profile 文件"和"更高优先级"画了等号
面试官内心 OS:"这个候选人显然没有实际部署过 Spring Boot 应用。在生产环境中,我们通常在 jar 包外的 config 目录放配置文件,如果 jar 包内的 dev.yml 先加载,jar 包外的 prod.yml 覆盖了它,那 profile 激活的逻辑就全乱了。"
5.2 把加载顺序和生效顺序搞混
候选人原话:"Spring Boot 先加载 application.yml,然后加载 application-dev.yml,dev 覆盖主配置。"
正确理解:Spring Boot 是合并所有配置源,而不是先加载一个再加载另一个。加载顺序只是决定了当同一个 key 出现多次时,哪个值最终生效。合并时后面的覆盖前面的。
5.3 不知道 properties > yml
候选人原话:"application.properties 和 application.yml 是一样的,哪个都行。"
问题诊断:
- 不知道两者同时存在时的优先级差异
- 不知道 properties 的优先级更高
六、标准回答
6.1 P5 级别
"Spring Boot 会从多个位置加载配置文件,优先级从高到低是:命令行参数 > jar 包外 config 目录 > jar 包外根目录 > jar 包内。jar 包外的配置文件优先级比 jar 包内的高。properties 文件的优先级高于 yml 文件。"
6.2 P6 级别
"Spring Boot 的配置加载遵循'后面的覆盖前面的'原则。完整顺序是:命令行参数 --spring.config.additional-location > jar 包外 ./config/ > jar 包外 ./ > jar 包内 ./config/ > jar 包内 ./。
当 properties 和 yml 同时存在时,properties 的优先级更高。注意 @PropertySource 注解不支持加载 yml 文件,只支持 properties。
Profile 激活方式有多种:命令行参数 --spring.profiles.active、环境变量 SPRING_PROFILES_ACTIVE、JVM 参数 -Dspring.profiles.active。Spring Boot 2.4+ 引入了 spring.config.activate.on-profile 来声明式地指定 profile 所属。"
6.3 P7 级别
"这道题背后考的是 Spring Boot 配置体系的设计哲学——'约定大于配置',但又'允许覆盖'。
我之前在项目中遇到过一个坑:开发环境用的是 jar 包内的配置,打包时 profile 没改,导致生产环境用了开发环境的配置。后来我们在 CI/CD 流程中强制要求 spring.config.additional-location 必须指定为 jar 包外的 config 目录,这样配置和 jar 包解耦了,任何配置修改都不需要重新打包。
Spring Boot 3.x 的 profile 激活方式完全变了——移除了基于文件命名的 application-{profile}.yml 改成了 application.yml 内使用 spring.config.activate.on-profile。这对老项目迁移来说是个大工程。"
【面试官心理】
P7 的回答重点在于"生产踩坑"和"团队规范建设"。能说出"我们团队怎么解决这类问题"的候选人,面试官会高看一眼。