SpringBoot多環(huán)境配置踩坑指南
先說說我的項目情況
我目前維護的項目用的是 Spring Boot 2.5.15,配置文件的組織方式是這樣的:
resources/config/dev/hbase.properties
resources/config/dev/zk.properties
resources/config/dev/hbase.xml
resources/config/prod/hbase.properties
resources/config/prod/zk.properties
resources/config/prod/hbase.xml
代碼里也是五花八門:有用 @Value 注入的,有用 @ConfigurationProperties 的,還有硬編碼用 ClassLoader.getResourceAsStream() 讀取的。說實話,這種”歷史遺留”代碼,懂的都懂。
最近研究配置加載方式的時候,發(fā)現門道還挺多。今天就結合自己的理解,把這幾個常用參數徹底掰扯清楚。
一、-Xbootclasspath/a:JVM 級別的”后門”
這玩意兒到底干嘛的?
簡單來說,這是 JVM 的標準參數,用來在 Bootstrap ClassLoader 的搜索路徑末尾追加額外的類路徑。Bootstrap ClassLoader 是 JVM 最頂層的類加載器,負責加載核心類庫。
我什么時候用它?
主要是為了解決那種需要從 ClassLoader 直接讀取配置文件的場景。比如我項目里那些用 getResourceAsStream("xxx.properties") 的代碼,如果不加這個參數,有時候就讀不到外部配置文件。
用法示例
# Linux/Mac java -Xbootclasspath/a:/path/to/config -jar app.jar # Windows(注意用分號) java -Xbootclasspath/a:C:\path\to\config -jar app.jar
踩坑提醒
- 路徑分隔符:Linux 用
:,Windows 用;,搞錯了直接報錯 - 會改變 ClassLoader 的加載順序,有時候會引起一些詭異的類加載問題
二、-Dloader.path:Spring Boot 可執(zhí)行 Jar 的專屬武器
原理是啥?
這個參數是 Spring Boot 的 LaunchedURLClassLoader 專門識別的。當你打包成 Fat Jar 后,Spring Boot 會用自己定制的 ClassLoader 來加載類,而這個參數就是告訴它:”嘿,除了這些,再去這些地方找找”。
我能用它干嘛?
- 加載外部的配置文件
- 動態(tài)添加額外的 jar 包
- 實現某種程度上的”熱更新”(雖然不建議在生產環(huán)境這么玩)
用法示例
# Linux/Mac java -Dloader.path=/path/to/config,/path/to/lib -jar app.jar # Windows java -Dloader.path=C:\path\to\config;C:\path\to\lib -jar app.jar
實際應用場景
我現在的啟動腳本就是這樣寫的:
java -Dloader.path=/opt/myapp/config \
-Dspring.profiles.active=prod \
-jar myapp.jar這樣配置文件就可以放在 jar 包外面,改配置不用重新打包,運維同學也很開心。
三、spring.config.location:徹底接管配置加載
注意!這是”替換”不是”追加”
這個參數會完全覆蓋 Spring Boot 默認的配置文件搜索位置。默認情況下,Spring Boot 會按這個順序找配置:
file:./config/file:./classpath:/config/classpath:/
一旦你用了 spring.config.location,上面這些位置就都被忽略了,只加載你指定的位置。
三種設置方式
# 1. 命令行參數(優(yōu)先級最高) java -jar app.jar --spring.config.location=/path/to/config/ # 2. 系統(tǒng)屬性 java -Dspring.config.location=/path/to/config/ -jar app.jar # 3. 環(huán)境變量 export SPRING_CONFIG_LOCATION=/path/to/config/
我的建議
除非你有特殊需求,否則不要輕易用這個參數。一旦用了,默認的配置加載邏輯就全被 干掉了,很容易踩坑。
四、spring.config.additional-location:更友好的”追加”方式
和上面的區(qū)別
這個參數是追加而不是替換。它會在默認配置位置的基礎上,額外增加你指定的搜索路徑。
優(yōu)先級順序
spring.config.location指定的位置(最高)spring.config.additional-location指定的位置- 默認位置(最低)
這是我目前最推薦的方式
java -jar app.jar --spring.config.additional-location=/opt/myapp/config/
這樣既保留了 Spring Boot 的默認行為,又能加載外部的配置文件,兩全其美。
五、配置加載優(yōu)先級:一定要搞清楚
Spring Boot 的配置屬性優(yōu)先級從高到低:
- 命令行參數(
--server.port=8080) - Java 系統(tǒng)屬性(
System.getProperties()) - 操作系統(tǒng)環(huán)境變量
RandomValuePropertySource(${random.*})- Jar 包外部的 profile 配置文件
- Jar 包內部的 profile 配置文件
- Jar 包外部的 application.properties
- Jar 包內部的 application.properties
- @PropertySource 注解加載的配置
- 默認屬性(最低)
記住這個優(yōu)先級很重要,有時候配置沒生效,很可能就是優(yōu)先級被覆蓋了。
六、我的項目改造實錄
原來的問題
我項目里有一堆這樣的代碼:
InputStream is = HbaseConfig.class.getClassLoader()
.getResourceAsStream("hbase.properties");這種寫法有幾個問題:
- 只能從 classpath 根目錄加載
- 無法加載
config/dev/hbase.properties這種嵌套路徑 - 不支持 Spring Boot 的配置優(yōu)先級機制
改造方案
方案一:使用 Spring 的 ResourceLoader(推薦)
@Autowired
private ResourceLoader resourceLoader;
public void loadConfig() throws IOException {
Resource resource = resourceLoader.getResource(
"classpath:config/" + env + "/hbase.properties"
);
Properties props = new Properties();
props.load(resource.getInputStream());
}方案二:直接用 @Value 注入
@Value("classpath:config/${spring.profiles.active}/hbase.properties")
private Resource hbaseConfig;方案三:徹底擁抱 Spring Boot(最佳)
把配置文件內容合并到 application-dev.yml 和 application-prod.yml 中,完全交給 Spring Boot 管理。
七、各環(huán)境的最佳實踐
開發(fā)環(huán)境(IDE 中運行)
項目結構:
project/
├── src/main/resources/
│ ├── application.yml # 主配置
│ ├── application-dev.yml # 開發(fā)環(huán)境
│ ├── application-prod.yml # 生產環(huán)境
│ └── config/
│ ├── dev/
│ └── prod/
└── external-config/ # 外部配置(gitignore)
└── application-local.yml # 個人本地配置
IDE 啟動參數:
-Dspring.profiles.active=dev -Dspring.config.additional-location=file:./external-config/
Linux 生產環(huán)境
目錄結構:
/opt/myapp/
├── app.jar
├── config/
│ ├── application.yml
│ ├── hbase.properties
│ └── zk.properties
└── logs/
啟動腳本:
#!/bin/bash APP_HOME=/opt/myapp CONFIG_DIR=$APP_HOME/config LOG_DIR=$APP_HOME/logs mkdir -p $LOG_DIR java \ -Dspring.profiles.active=prod \ -Dspring.config.additional-location=file:$CONFIG_DIR/ \ -Dloader.path=$CONFIG_DIR \ -Xms512m \ -Xmx1024m \ -jar $APP_HOME/app.jar \ >> $LOG_DIR/app.log 2>&1 & echo $! > $APP_HOME/app.pid
Systemd 服務配置:
[Unit] Description=My Spring Boot Application After=syslog.target [Service] User=appuser WorkingDirectory=/opt/myapp Environment="SPRING_PROFILES_ACTIVE=prod" Environment="SPRING_CONFIG_ADDITIONAL_LOCATION=file:/opt/myapp/config/" ExecStart=/usr/bin/java -jar /opt/myapp/app.jar Restart=on-failure [Install] WantedBy=multi-user.target
Windows 生產環(huán)境
目錄結構:
C:\Apps\MyApp\
├── app.jar
├── config\
│ ├── application.yml
│ ├── hbase.properties
│ └── zk.properties
└── start.bat
啟動腳本:
@echo off setlocal set APP_HOME=C:\Apps\MyApp set CONFIG_DIR=%APP_HOME%\config java ^ -Dspring.profiles.active=prod ^ -Dspring.config.additional-location=file:%CONFIG_DIR%/ ^ -Dloader.path=%CONFIG_DIR% ^ -Xms512m ^ -Xmx1024m ^ -jar %APP_HOME%\app.jar endlocal
八、最后:我的選擇建議
| 場景 | 推薦參數 | 原因 |
|---|---|---|
| 開發(fā)環(huán)境 | spring.config.additional-location | 保留默認行為,方便調試 |
| 生產環(huán)境(Linux) | spring.config.additional-location + loader.path | 靈活、可控 |
| 生產環(huán)境(Windows) | spring.config.additional-location + loader.path | 同上 |
| 需要 ClassLoader 讀取 | -Xbootclasspath/a | 兼容遺留代碼 |
| 完全自定義配置位置 | spring.config.location | 特殊需求專用 |
最后說一句:不要過度設計。對于大部分項目來說,spring.config.additional-location 配合 spring.profiles.active 已經夠用了。除非你真的有特殊需求,否則沒必要搞得太復雜。
到此這篇關于SpringBoot多環(huán)境配置踩坑指南的文章就介紹到這了,更多相關SpringBoot多環(huán)境配置內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java基于Spire Cloud Excel把Excel轉換成PDF
這篇文章主要介紹了Java基于Spire Cloud Excel把Excel轉換成PDF,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-05-05
Java線程池隊列PriorityBlockingQueue原理分析
這篇文章主要介紹了Java線程池隊列PriorityBlockingQueue原理分析,PriorityBlockingQueue隊列是?JDK1.5?的時候出來的一個阻塞隊列,但是該隊列入隊的時候是不會阻塞的,永遠會加到隊尾,需要的朋友可以參考下2023-12-12
@ConfigurationProperties與EnableConfigurationProperties使用及說明
這段文章詳細介紹了@ConfigurationProperties和@enableConfigurationProperties注解在Spring框架中的應用,通過實例展示了如何實現配置文件與實體類屬性的注入,并強調了@enableConfigurationProperties注解的正確使用場景和注意事項2026-06-06
Java中ScheduledExecutorService介紹和使用案例(推薦)
ScheduledExecutorService是Java并發(fā)包中的接口,用于安排任務在給定延遲后運行或定期執(zhí)行,它繼承自ExecutorService,具有線程池特性,可復用線程,提高效率,本文主要介紹java中的ScheduledExecutorService介紹和使用案例,感興趣的朋友一起看看吧2024-10-10

