從 Spring Boot 2.4 開始,設定處理機制由舊版的
ConfigFileApplicationListener全面重構為ConfigDataEnvironmentPostProcessor。若通過命令行、環境變數或spring.profiles.active指定了不存在的設定文件,或者使用spring.config.import引入了缺失的資源且未聲明optional:前綴,Spring Boot 啟動時將嚴格校驗並直接拋出ConfigDataLocationNotFoundException。
Issue & Env(案發現場與環境)
在本地開發或 CI/CD 流水線中部署 Spring Boot 2.4+ / 3.x 應用時,指定環境 profile 或加載外部化掛載文件常遭遇容器無法拉起的問題:
- 受影響版本:Spring Boot 2.4.0 ~ 3.3.x(引入 ConfigData 機制後的所有版本)
- 運行時環境:OpenJDK 17 / 21,Docker / Kubernetes Pod / 本地 IDEA
- 觸發條件:
spring.profiles.active指定的 profile 文件不存在(如筆誤或.gitignore漏傳)。- 使用
spring.config.import引用了掛載路徑,但在無該卷掛載的環境下未標明可選。
StackTrace(堆疊日誌)
控制台直接拋出例外並快速失敗終止 JVM,阻斷容器拉起:
2026-09-02 10:14:22.841 ERROR 1 --- [main] o.s.boot.SpringApplication : Application run failed
org.springframework.boot.context.config.ConfigDataLocationNotFoundException: Config data location 'classpath:/application-dev.yml' does not exist
at org.springframework.boot.context.config.ConfigDataLocationNotFoundException.create(ConfigDataLocationNotFoundException.java:70)
at org.springframework.boot.context.config.StandardConfigDataLocationResolver.getReferences(StandardConfigDataLocationResolver.java:152)
at org.springframework.boot.context.config.StandardConfigDataLocationResolver.resolve(StandardConfigDataLocationResolver.java:128)
at org.springframework.boot.context.config.ConfigDataLocationResolvers.resolve(ConfigDataLocationResolvers.java:114)
at org.springframework.boot.context.config.ConfigDataEnvironment.processInitial(ConfigDataEnvironment.java:240)
at org.springframework.boot.context.config.ConfigDataEnvironment.processAndApply(ConfigDataEnvironment.java:198)
at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:96)
at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent(EnvironmentPostProcessorApplicationListener.java:109)
at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEvent(EnvironmentPostProcessorApplicationListener.java:94)
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:178)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:171)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:145)
at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:85)
at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:66)
at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:344)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:302)
at com.example.demo.DemoApplication.main(DemoApplication.java:12)
Reproduce(復現程式碼)
在 src/main/resources/ 下僅放置預設的 application.yml:
spring:
application:
name: order-service
profiles:
active: dev
config:
import:
- "file:/etc/secrets/config.properties"
但項目中並沒有 application-dev.yml(可能因拼寫為 application-devel.yml,或構建工具排除),同時宿主機目錄 /etc/secrets/config.properties 不存在。
運行命令觸發構建與啟動:
mvn spring-boot:run
框架在引導階段觸發 ConfigDataLocationNotFoundException 並直接退出進程。
Root Cause(根因分析)
在 Spring Boot 2.4 之前,框架對缺失的 profile 設定文件預設採取靜默容忍策略,如果未找到 application-dev.yml,通常只是忽略該文件並繼續使用主設定。
自 Spring Boot 2.4 引入全新的 ConfigData API 起,底層由 StandardConfigDataLocationResolver 與 ConfigDataEnvironment 嚴格把關:
- 顯式指定被判定為強制依賴:當系統解析到顯式設定的激活環境(如
-Dspring.profiles.active=dev)或顯式引用的導入路徑(spring.config.import)時,框架判定開發者是有意加載該資源的。 - 缺乏可選標記(Optional Prefix):如果目標文件為非必選項(例如容器內可能存在也可能不存在的掛載卷),但設定中未加上
optional:前綴,Spring Boot 會認為關鍵設定遺失。為了防止系統帶著半殘的設定啟動導致隱蔽的運行時災難,設計上選擇快速失敗(Fail-Fast)。 - 打包資源過濾:在多模塊 Maven / Gradle 工程中,
resources設定若未包含指定 profile 的文件名模式,導致 jar 包內實際缺失對應資源。
The Fix(解決方案)
方案 1:檢查 Profile 拼寫與構建資源打包
確認 src/main/resources 下的文件命名完全符合 application-{profile}.yml 或 application-{profile}.properties 規範。如果使用 Maven 構建,確認 pom.xml 中未誤排 YAML 文件:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>application*.yml</include>
<include>application*.properties</include>
</includes>
</resource>
</resources>
</build>
方案 2:為外部導入路徑添加 optional 前綴
如果外部設定(如 K8s Secret、ConfigMap 卷或外部掛載文件)只在特定宿主機存在,必須使用 optional: 前綴進行聲明:
spring:
config:
import:
- "optional:file:/etc/secrets/config.properties"
- "optional:classpath:custom-config.yml"
增加 optional: 之後,StandardConfigDataLocationResolver 若探測到文件缺失,將跳過加載而不會拋出 ConfigDataLocationNotFoundException。
方案 3:使用 debug 模式排查實際生效路徑
在啟動參數中加入 --debug 選項:
java -jar target/demo-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev --debug
控制台會輸出完整的 ConditionsEvaluationReport 以及設定加載位置列表,明確標出當前掃描的 classpath 根目錄以及各設定源的來源文件路徑。
