一、結論
Spring Boot 中,位置越靠后優先級越高,外部配置壓倒內部配置,命令行參數擁有最高優先權。
案例:
在一次生產事故中,某團隊通過 application-prod.properties
將服務端口設為 9000
,但某運維人員在啟動命令中加入了 --server.port=8080
。最終服務運行在了錯誤端口,接口全部掛掉,業務中斷近10分鐘。
原因?配置優先級未搞清楚。
這篇文章將帶你系統掌握:
- Spring Boot 配置文件與配置源的優先級規則
- 多環境配置加載機制與沖突排查技巧
- 常見場景下如何安全合理管理配置
二、配置優先級結構化剖析
1. 配置文件物理位置優先級
Spring Boot 啟動時會自動加載配置文件,并根據物理位置順序決定優先級。
優先級 | 文件位置 | 示例路徑 | 優先級趨勢 |
---|---|---|---|
1 | classpath:/ | src/main/resources/application.properties | 🡻最低 |
2 | classpath:/config/ | src/main/resources/config/ | |
3 | file:./ | 程序運行目錄下的application.properties | |
4 | file:./config/ | 程序運行目錄下的config/application.properties | |
5 | file:./config/*/ | 運行目錄下多層子目錄中的配置文件 | 🡹最高 |
舉個例子:
假設配置如下:1. classpath:/application.propertiesserver.port=8080app.name=MyApp2. file:./application.propertiesserver.port=90903. file:./config/application.propertiesapp.name=ProdApp最終生效的是:
- server.port=9090(外部覆蓋內部)
- app.name=ProdApp(優先級更高的 config 文件覆蓋)
2. 配置源類型優先級
Spring Boot 不僅從配置文件讀取屬性,還可能從環境變量、命令行等多種來源加載配置。這些配置源的優先級也有先后之分。
配置源優先級圖譜
關鍵加載順序(由低到高):
SpringApplication.setDefaultProperties
@PropertySource("...")
- 配置文件(.properties / .yml)
- 環境變量(如
export SERVER_PORT=9090
) - JVM系統參數(
-Dserver.port=9090
) SPRING_APPLICATION_JSON
環境變量(支持JSON格式)- 命令行參數(最高優先級)
實戰例子:
java -jar app.jar --server.port=9999
即使 .properties
中配置了 server.port=8080
,最終還是 9999
生效。
3. 環境配置覆蓋機制(多環境配置)
Spring Boot 支持通過 profile 來管理多環境配置(如 dev/test/prod),這背后的核心是 profile-specific 配置文件加載策略。
多環境配置加載邏輯:
加載順序如下(生效配置會覆蓋默認):
application.properties
(默認配置)application-{profile}.properties
(特定環境覆蓋)
激活方式三選一:
-
配置文件中指定:
spring.profiles.active=prod
-
啟動參數中指定:
--spring.profiles.active=prod
-
環境變量指定:
export SPRING_PROFILES_ACTIVE=prod
多Profile疊加場景:
# application.properties
spring.profiles.active=dev,test# application-dev.properties
log.level=DEBUG# application-test.properties
log.level=INFO
最終哪個生效?后激活的profile生效(test > dev),即
INFO
。
4. 配置驗證(排查工具)
當你困惑“到底哪個配置生效了?”可以用以下三種方式排查:
① Actuator /env
端點
curl http://localhost:8080/actuator/env
輸出內容會告訴你每個屬性的來源。
② 日志輸出
Spring Boot 啟動時會打印配置文件查找路徑:
Config data locations:- file:./config/- file:./- classpath:/config/- classpath:/
③ 代碼方式打印配置來源
@Autowired
Environment environment;@PostConstruct
public void printPropertySources() {for (PropertySource<?> ps : ((AbstractEnvironment) environment).getPropertySources()) {System.out.println("Source: " + ps.getName());System.out.println("server.port = " + ps.getProperty("server.port"));}
}
三、典型實戰場景解析
場景1:開發 vs 生產配置分離
建議:
- 開發配置放在 jar 內(如
application-dev.properties
) - 生產配置放在外部
./config/application-prod.properties
- 啟動時用
--spring.profiles.active=prod
激活
這樣可以在不重新打包的前提下,實現靈活環境切換。
場景2:容器化部署配置(Docker/K8s)
推薦順序:
- 命令行參數(覆蓋一切)
- 環境變量(配合 K8s Secret/ConfigMap 注入)
- 文件掛載(將配置掛載至
/config/
)
樣例Dockerfile:
ENV SPRING_PROFILES_ACTIVE=prod
COPY config/ /config/
ENTRYPOINT ["java", "-jar", "app.jar", "--server.port=9090"]
場景3:配置安全分層
做法建議:
- 敏感配置(如密碼)通過 環境變量 注入
- 不敏感配置 保留在
.properties
文件中 - 使用
@ConfigurationProperties
+@Validated
加強類型約束
四、總結
核心口訣:
“外大于內,命大于環,動大于靜”
- 外部配置 > 內部配置(jar包內)
- 命令行 > 環境變量 > 文件配置
- 動態配置源(命令、env)比靜態文件優先
避坑建議:
- 避免把敏感數據寫進
@PropertySource
注解中(不安全且優先級低) - 不要在多個位置重復配置同一屬性,容易誤判生效值
- 注意profile加載順序,后指定的覆蓋前面的
拓展思考:
如果你使用配置中心(如 Nacos、Apollo),你還需考慮:
- 配置中心刷新機制(如Spring Cloud Config的監聽刷新)
- 本地配置是否允許覆蓋遠程配置
- 如何記錄配置來源和變更歷史(方便審計和回溯)
結語
掌握配置優先級,是一個成熟Spring Boot工程師的基本功。別讓一行配置毀掉一條生產鏈路。借助本文的方法論和工具手段,你可以輕松駕馭復雜環境,讓配置服務于系統,而不是系統為配置買單。