Spring Boot讀取外部配置檔案失敗,原因絕對出乎你意料

青石路發表於2024-12-03

開心一刻

今天和相親物件見面,特意打扮了一番
見完面回到家後我給她發微信
我:我今天的形象怎麼樣
她:挺白淨亮眼的
我:頭髮不油吧
她:反光,沒看清
我:???

反光沒看清

知識回顧

在我們的實際開發工程中,打包的 jar 通常會包含配置檔案(例如:application.yml)來作為預設配置檔案,然後在不同的環境用外部配置檔案來覆蓋 jar 包中配置檔案配置的某些配置項,當然也可以全量覆蓋;Spring Boot 關於外部配置(Externalized Configuration)有這麼一段說明

External Application Properties

我給大家翻譯一下

應用啟動時,Spring Boot會自動從以下位置查詢並載入 application.propertiesapplication.yaml

  1. 從類路徑

    a. 類路徑根目錄

    classpath根目錄

    src/main/resources 下的檔案,預設情況下會被打包到類路徑(classpath)下

    b. 類路徑下的 config

  2. 從當前目錄

    a. 當前目錄,也就 jar 所在目錄

    b. 當前目錄下的 config 目錄

    c. 當前目錄下的 config 目錄的直接子目錄

Spring Boot 會按如上順序從上往下查詢並載入 application.propertiesapplication.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.timeshttp.url)值,當應用中的全部屬性都設定完成之後,Spring 會呼叫 afterPropertiesSet 方法,日誌輸出 retryTimeshttpUrl 的值。結合上述的載入順序,我們來驗證下是否如 Spring Boot 官方所說

  1. 從類路徑

    這個我們只驗證一種情況:類路徑下只存在 application.yml;驗證非常簡單,直接在 jar 所在目錄下

    類路徑下配置檔案生效

    執行

    java -jar spring-boot-external-config-1.0-SNAPSHOT.jar
    

    可以看到輸出如下

    類路徑下配置檔案生效驗證

    是不是沒毛病?

  2. 從當前目錄

    在 jar 所在目錄下放一個 application.yml

    當前目錄下配置檔案

    其內容如下

    retry:
      times: 2
    

    我特意拿掉了配置項 http.url,同樣直接執行

    java -jar spring-boot-external-config-1.0-SNAPSHOT.jar
    

    輸出結果如下

    當前目錄下配置檔案生效

    紅框框住的值與藍框框住的值,它們分別來自哪個配置檔案,你們應該知道吧;也如 Spring Boot 官方所說,非常正常。我們再在當前目錄下加個 config 目錄

    當前目錄下config配置檔案

    其下放一個 application.yml,內容如下

    retry:
      times: 9
    http:
      url: http://127.0.0.1:8080
    

    執行結果如下

    當前目錄下config配置檔案驗證

    也如 Spring Boot 官方描述的那樣,沒有任何毛病

    為了保持部署結構的簡單清晰,我們往往會採用 config 目錄的這種方式來放外部配置檔案,包括應用配置檔案、日誌配置檔案等等;但如果外部配置檔案跟當前目錄沒有直接關係了,比如在其他盤或者其他目錄下,那麼如何指定外部配置檔案呢?有但不限於如下兩種(仔細斟酌如下寫法是否正確

    1. java -jar spring-boot-external-config-1.0-SNAPSHOT.jar -Dspring.config.location=外部檔案路徑
    2. 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上類路徑配置

這是 jar 中預設配置檔案的配置值,沒問題吧?我們再上傳 jar 同級目錄下的 config 資料夾,上傳後目錄結構如下

Linux上目錄結構

執行後日志輸出如下

linux上config配置

也和在 windows 上的演示結果一樣,很正常。絕大部分情況下,我們的配置檔案不止一個,所以從命名的準確性考慮,我們往往會將 config 目錄命名成 configs

linux上configs配置

那麼此時啟動命令就需要調整下了

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

這輸出的還是 jar 包中的配置項值,並非 configs 目錄下 application.yml 中的配置項值,讀取外部配置檔案失敗了?帶著疑問我們嘗試下 -- 方式

java -jar spring-boot-external-config-1.0-SNAPSHOT.jar --spring.config.location=configs/application.yml

發現能夠正常載入

linux上configs配置--

為什麼 -D 的方式會失敗?

why

解決問題

出題出在哪,就出在 java 命令引數的順序上,我們看下 java 命令的幫助文件

Spring Boot讀取外部配置檔案失敗,原因絕對出乎你意料

也就是說 -D-- 需要在 -jar 前面,所以正確讀取 configs 目錄下配置檔案的命令應該是

java -Dspring.config.location=configs/application.yml -jar spring-boot-external-config-1.0-SNAPSHOT.jar

執行結果如下

正確載入外部目錄的方式

總結

  1. 常用載入外部配置檔案的命令引數

    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 命令列引數。兩種方式有其各自的順序寫法,切勿張冠李戴!

  2. 推薦做法

    在 jar 包所在目錄建立 config 資料夾,將外部配置檔案置於該 config 資料夾下,啟動的時候可以減少啟動引數,那麼出錯的機率就會降低

相關文章