開心一刻
今天和相親物件見面,特意打扮了一番
見完面回到家後我給她發微信
我:我今天的形象怎麼樣
她:挺白淨亮眼的
我:頭髮不油吧
她:反光,沒看清
我:???
![反光沒看清](https://i.iter01.com/images/3b470926f0274ba9392c773d71906abd97b5f3b69a85dffdd2a9134aebb92297.png)
知識回顧
在我們的實際開發工程中,打包的 jar 通常會包含配置檔案(例如:application.yml
)來作為預設配置檔案,然後在不同的環境用外部配置檔案來覆蓋 jar 包中配置檔案配置的某些配置項,當然也可以全量覆蓋;Spring Boot 關於外部配置(Externalized Configuration)有這麼一段說明
![External Application Properties](https://i.iter01.com/images/344a7bf61dfe4802a464f74c9029a1003ac07c019a9dc6e731a0e72bf4abb0d5.png)
我給大家翻譯一下
應用啟動時,Spring Boot會自動從以下位置查詢並載入
application.properties
和application.yaml
從類路徑
a. 類路徑根目錄
src/main/resources
下的檔案,預設情況下會被打包到類路徑(classpath)下b. 類路徑下的
config
包從當前目錄
a. 當前目錄,也就 jar 所在目錄
b. 當前目錄下的
config
目錄c. 當前目錄下的
config
目錄的直接子目錄Spring Boot 會按如上順序從上往下查詢並載入
application.properties
和application.yaml
,如果配置項重新命名了,後載入的值會覆蓋掉之前載入的值。配置檔案中的配置項會以PropertySources
例項的形式新增到 Spring 環境中
我們來看個示例:spring-boot-external-config,程式碼非常簡單,我們只需要關注 ConfigDemo.java
/**
* @author: 青石路
*/
@Component
public class ConfigDemo implements InitializingBean {
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigDemo.class);
@Value("${retry.times}")
private Integer retryTimes;
@Value("${http.url}")
private String httpUrl;
@Override
public void afterPropertiesSet() throws Exception {
LOGGER.info("retryTimes:{}, httpUrl:{}", retryTimes, httpUrl);
}
}
application.yml
內容如下
retry:
times: 6
http:
url: http://localhost:8080
我相信你們都能看懂,透過 Spring 注入進來兩個配置項(retry.times
和 http.url
)值,當應用中的全部屬性都設定完成之後,Spring 會呼叫 afterPropertiesSet
方法,日誌輸出 retryTimes
和 httpUrl
的值。結合上述的載入順序,我們來驗證下是否如 Spring Boot 官方所說
-
從類路徑
這個我們只驗證一種情況:類路徑下只存在
application.yml
;驗證非常簡單,直接在 jar 所在目錄下執行
java -jar spring-boot-external-config-1.0-SNAPSHOT.jar
可以看到輸出如下
是不是沒毛病?
-
從當前目錄
在 jar 所在目錄下放一個
application.yml
其內容如下
retry: times: 2
我特意拿掉了配置項
http.url
,同樣直接執行java -jar spring-boot-external-config-1.0-SNAPSHOT.jar
輸出結果如下
紅框框住的值與藍框框住的值,它們分別來自哪個配置檔案,你們應該知道吧;也如 Spring Boot 官方所說,非常正常。我們再在當前目錄下加個
config
目錄其下放一個
application.yml
,內容如下retry: times: 9 http: url: http://127.0.0.1:8080
執行結果如下
也如 Spring Boot 官方描述的那樣,沒有任何毛病
為了保持部署結構的簡單清晰,我們往往會採用
config
目錄的這種方式來放外部配置檔案,包括應用配置檔案、日誌配置檔案等等;但如果外部配置檔案跟當前目錄沒有直接關係了,比如在其他盤或者其他目錄下,那麼如何指定外部配置檔案呢?有但不限於如下兩種(仔細斟酌如下寫法是否正確)- java -jar spring-boot-external-config-1.0-SNAPSHOT.jar -Dspring.config.location=外部檔案路徑
- java -jar spring-boot-external-config-1.0-SNAPSHOT.jar --spring.config.location=外部檔案路徑
外部檔案按路徑可以是絕對路徑,也可以是相對路徑,如果是相對路徑,則以 jar 包所在的目錄開始算
復現問題
一切準備就緒,我們往 Linux
伺服器上部署,先將 spring-boot-external-config-1.0-SNAPSHOT.jar
上傳到伺服器,執行
java -jar spring-boot-external-config-1.0-SNAPSHOT.jar
日誌輸出如下
![linux上類路徑配置](https://i.iter01.com/images/7c7a6584b12f552bf9c2488939fc51f53e3841a48dddb16e500a28aca16b57dd.png)
這是 jar 中預設配置檔案的配置值,沒問題吧?我們再上傳 jar 同級目錄下的 config 資料夾,上傳後目錄結構如下
![Linux上目錄結構](https://i.iter01.com/images/410bd38abab26fc5223f139a1b3880a858e9e1c3773465eef67321b73da56a87.png)
執行後日志輸出如下
![linux上config配置](https://i.iter01.com/images/7d4667670531efa0908c7d537eda18848d07c29535b1a6f763a284e0ad9673bf.png)
也和在 windows 上的演示結果一樣,很正常。絕大部分情況下,我們的配置檔案不止一個,所以從命名的準確性考慮,我們往往會將 config
目錄命名成 configs
![linux上configs配置](https://i.iter01.com/images/17b2515189b8e3f9ff995fde90e798baae07933e94c15e0aab2809f0f16c9e00.png)
那麼此時啟動命令就需要調整下了
java -jar spring-boot-external-config-1.0-SNAPSHOT.jar -Dspring.config.location=configs/application.yml
或
java -jar spring-boot-external-config-1.0-SNAPSHOT.jar --spring.config.location=configs/application.yml
我們以 -D
的形式啟動下,日誌輸出如下
![linux上configs配置-D](https://i.iter01.com/images/d9bab1fe468e095113fb6a4177dce761c0ca306125fcf92435d917622ab34663.png)
這輸出的還是 jar 包中的配置項值,並非 configs 目錄下 application.yml 中的配置項值,讀取外部配置檔案失敗了?帶著疑問我們嘗試下 --
方式
java -jar spring-boot-external-config-1.0-SNAPSHOT.jar --spring.config.location=configs/application.yml
發現能夠正常載入
![linux上configs配置--](https://i.iter01.com/images/6e0c913b3376e03a09db9020406954d051450738efdf7042cd3381315d42eea7.png)
為什麼 -D
的方式會失敗?
![why](https://i.iter01.com/images/6eff18406d692ee20905a292d1f1f8456fdd638bea0427e054564d60786bb013.png)
解決問題
出題出在哪,就出在 java 命令引數的順序上,我們看下 java
命令的幫助文件
![Spring Boot讀取外部配置檔案失敗,原因絕對出乎你意料](https://i.iter01.com/images/16dc42958a76e7b2927feaddc4e0d06c14c15e2e518c3040afded97cbd54f90d.png)
也就是說 -D
或 --
需要在 -jar
前面,所以正確讀取 configs 目錄下配置檔案的命令應該是
java -Dspring.config.location=configs/application.yml -jar spring-boot-external-config-1.0-SNAPSHOT.jar
執行結果如下
![正確載入外部目錄的方式](https://i.iter01.com/images/0608d8543b229bf8e9c048aef6e24c7bca490fc702470f128988098cffbc4255.png)
總結
-
常用載入外部配置檔案的命令引數
java -Dspring.config.location=configs/application.yml -jar spring-boot-external-config-1.0-SNAPSHOT.jar
或
java -jar spring-boot-external-config-1.0-SNAPSHOT.jar --spring.config.location=configs/application.yml
-D
緊隨java
之後,在-jar
之前,是 JVM 引數;--
在 jar 名稱之後,是 Spring Boot 命令列引數。兩種方式有其各自的順序寫法,切勿張冠李戴! -
推薦做法
在 jar 包所在目錄建立
config
資料夾,將外部配置檔案置於該 config 資料夾下,啟動的時候可以減少啟動引數,那麼出錯的機率就會降低