Spring Boot 2.4 中的配置檔處理

工程 | Phil Webb | 2020 年 8 月 14 日 | ...

Spring Boot 2.4.0.M2 已經發布,它為 application.propertiesapplication.yml 檔案的載入方式帶來了一些有趣的變更。

如果您的應用程式使用相當典型的設置,僅使用單個 application.propertiesapplication.yml 檔案,那麼您可能不會注意到任何差異。但是,如果您的應用程式使用更複雜的設置(例如特定配置文件的屬性),您可能需要繼續閱讀以了解我們所做的更改以及原因。

我們為何進行這些變更

在最近的 Spring Boot 版本中,我們一直努力改進對 Kubernetes 的支援。我們想在 Spring Boot 2.3 中添加的一個功能,但未能實現的是對 volume mounted configuration 的支援。

Volume mounted configuration 是 Kubernetes 的一個流行功能,它使用 ConfigMap 指令將配置直接顯示在檔案系統上。您可以掛載包含多個鍵和值的 YAML 完整檔案,也可以使用更簡單的目錄樹格式,其中檔名是鍵,檔案內容是值。

我們希望提供對兩者的支援,並且以一種感覺與我們現有的 application.propertiesapplication.yml 支援一起使用的方式。為此,我們需要觸摸可怕的 ConfigFileApplicationListener 類別。

ConfigFileApplicationListener 的問題

幾年前,一些有趣的來自電玩遊戲 Trap Adventure 2 的剪輯開始流傳。它們非常適合類比軟體中可能發生的情況。有時您會發現自己擁有一些非常難以變更的程式碼區域。在 Spring Boot 中,ConfigFileApplicationListener 最終成為這些“陷阱冒險”之一。

並不是程式碼寫得很差或缺少測試。只是當我們向其中添加功能時,最終會把自己搞得一團糟。

我們程式碼中的兩個主要問題與特定配置文件的文件(主要是在 YAML 中)有關。即

  • 您可以從特定配置文件的文件中啟用其他配置文件。

  • 很難知道將添加文件的順序。

以下面的範例為例

security.user.password: usera

spring.profiles: local security.user.password: userb runlocal: true

spring.profiles: !dev spring.profiles.include: local security.user.password: userc

在這裡,我們有一個多文件 YAML 檔案(一個由三個邏輯文件組成的單個檔案,由 --- 分隔)。

如果您使用 --spring.profiles.active=prod 執行,security.user.password 的值是什麼?runlocal 屬性是否已設定?您確定嗎?由於在處理時未啟用配置文件,因此是否甚至包含中間文件?

我們經常收到有關此檔案處理邏輯的問題,但每當我們嘗試修復它們時,都會導致其他人的問題。我們最終決定,前進的唯一方法是重新思考整個事情。

因此,在 Spring Boot 2.4 中,我們計劃對載入屬性和 YAML 檔案的方式進行兩項重大變更

  1. 文件將按照定義的順序載入。

  2. 無法再從特定配置文件的文件中啟用配置文件。

文件順序

從 Spring Boot 2.4 開始,在載入屬性和 YAML 檔案時,將套用一個簡單的規則。檔案中較低宣告的屬性將覆蓋較高的屬性。

這遵循純舊 .properties 檔案已經使用的相同排序規則。將每一行都視為將一個條目放入 Map 中。當將具有相同鍵的新值放入 Map 中時,將替換任何現有條目。

遵循這些規則,給定一個多文件 YAML 檔案,較低的文件將覆蓋較高的文件中的值

test: "value"

test: "overridden-value"

多文件屬性檔案

使用 Spring Boot 2.4,我們決定將類似 YAML 的多文件支援引入 Java 屬性檔案。多文件屬性檔案使用註解 (#) 後面接著熟悉的三個破折號表示法來分割文件(我們選擇使用註解,以便現有的 IDE 工具不會中斷)。

例如,上面 YAML 片段的屬性等效項將是

test=value #--- test=overridden-value

特定配置文件的文件

上面的範例有點人為,因為總是覆蓋一個值沒有任何意義。更常見的設定是宣告第二個文件僅在特定配置文件處於活動狀態時才有效。

在 Spring Boot 2.3 中,您將使用 spring.profiles 鍵來執行此操作。使用 Spring Boot 2.4,我們決定將屬性變更為 spring.config.activate.on-profile

例如,如果我們只想在 dev 配置文件處於活動狀態時覆寫 test,我們可以使用以下程式碼

test=value #--- spring.config.activate.on-profile=dev test=overridden-value

配置文件啟用

您仍然可以使用 spring.profiles.active 屬性從 application.propertiesapplication.yaml 檔案啟用或包含配置文件。

例如,以下是完全有效的

test=value spring.profiles.active=local #--- spring.config.activate.on-profile=dev test=覆寫的值

有一件事你將不再被允許做,就是將該屬性與 spring.config.activate.on-profile 結合使用。例如,以下檔案現在會拋出例外

test=value #--- spring.config.activate.on-profile=dev spring.profiles.active=local # 將會失敗 test=覆寫的值

我們希望這個新的限制最終能讓你的 application.propertiesapplication.yml 檔案更容易理解和推論。我們也希望它能讓 Spring Boot 本身更容易管理和維護。然而,我們也意識到至少有一種有效的用例,人們希望將一個 profile 擴展成多個子 profile。為了支持這一點,我們正在添加一個名為 "profile groups" 的功能。

Profile Groups(Profile 群組)

Profile 群組是 Spring Boot 2.4 中的一項新功能,它允許您將單個 profile 擴展成多個子 profile。例如,假設你有一組複雜的 @Configuration 類別,你使用 @Profile 註解有條件地啟用它們。你可能有一個使用 @Profile("proddb") 的資料庫配置、一個使用 @Profile("prodmq") 的訊息配置等等。

使用多個離散的 profile 可能會使你的程式碼更容易推論,但對於部署來說並不理想。你不想強迫使用者記住他們必須總是同時啟用 proddbprodmqprodmetrics 等等。相反,你只是想讓他們能夠啟用單個 prod profile。群組允許你做到這一點。

要定義一個群組,你可以在你的 application.propertiesapplication.yml 檔案中使用 spring.profiles.group 屬性。例如

spring.profiles.group.prod=proddb,prodmq,prodmetrics

匯入額外的配置

現在我們已經修復了配置檔案處理的基本問題,我們終於可以考慮我們想要提供的新功能了。我們在 Spring Boot 2.4 中提供的主要功能是支援匯入額外的配置。

在 Spring Boot 的早期版本中,很難匯入除了 application.propertiesapplication.yml 之外的額外屬性或 yaml 檔案。你可以使用 spring.config.additional-location 屬性,但你需要很早設定它,並且它在可以處理的檔案類型方面受到相當大的限制。

在最新的里程碑版本中,你可以直接在你的 application.propertiesapplication.yml 檔案中使用新的 spring.config.import 屬性。例如,你可能想要匯入一個 "git ignored" 的 developer.properties 檔案,以便你的團隊中的任何開發人員都可以快速地更改僅適用於他們的屬性

application.name=myapp spring.config.import=developer.properties

你甚至可以將 spring.config.import 宣告與 spring.config.activate.on-profile 屬性結合使用。例如,這裡我們只在 prod profile 啟用時才載入 prod.properties

spring.config.activate.on-profile=prod spring.config.import=prod.properties

匯入可以被認為是插入在宣告它們的文件下方的額外文件。它們遵循與常規多文件文件相同的由上而下的排序:一個匯入只會被匯入一次,無論它被宣告了多少次。

Volume Mounted Configuration Trees(Volume 掛載的配置樹)

匯入定義使用類似 URL 的語法作為它們的值。如果你的位置沒有字首,它會被認為是一個常規檔案或資料夾。但是,如果你使用 configtree: 字首,你就是在告訴 Spring Boot,你期望在該位置有一個 Kubernetes 樣式的 volume 掛載的配置樹。

例如,你可以在你的 application.properties 中宣告以下內容

spring.config.import=configtree:/etc/config

如果你有以下掛載的內容

etc/ +- config/ +- my/ | +- application +- test

你最終會在你的 Spring Environment 中得到 my.applicationtest 屬性。my.application 的值將會是 /etc/config/my/application 的內容,而 test 的值將會是 /etc/config/test 的內容。

Cloud Platform Activation(雲端平台啟用)

如果你只想讓 volume 掛載的配置樹 (或者任何屬性) 在特定的雲端平台上啟用,你可以使用 spring.config.activate.on-cloud-platform 屬性。這與 spring.config.activate.on-profile 屬性的工作方式類似,但使用的是 CloudPlatform 值,而不是 profile 名稱。

如果我們只想在部署到 Kubernetes 時才啟用上面的 configtree 範例,我們可以這樣做

spring.config.activate.on-cloud-platform=kubernetes spring.config.import=configtree:/etc/config

Supporting Additional Locations(支援額外的位置)

spring.config.import 屬性中指定的位置字串是完全可插拔的,並且可以透過編寫一些自訂類別來擴展。我們預期第三方函式庫可能會在未來開始提供對自訂位置的支援。例如,你可以想像第三方 jar 檔案來支援諸如 archaius://…​vault://…​zookeeper://…​ 之類的位置。

如果你有興趣添加額外的位置支援,請查看 org.springframework.boot.context.config 套件中的 ConfigDataLocationResolverConfigDataLoader 的 javadoc。

Using Legacy Processing(使用舊版處理方式)

如果你正在升級現有的 Spring Boot 應用程式,並且你覺得使用所有這些新功能不自在,你可以切換回舊的處理器。要做到這一點,你可以將 spring.config.use-legacy-processing 設定為 true 到你的 application.propertiesapplication.yml 檔案。這應該會給你一個與 Spring Boot 2.3 應用程式相同的應用程式配置處理方式。

如果你發現你需要切換到舊版處理方式,因為我們遺漏了一個特定的用例,請在 GitHub 上提出 issue,我們會嘗試解決它。

Summary(總結)

我們希望新的配置資料處理類別是有用的,並且它們不會導致太多的升級痛苦。如果你想閱讀更多關於它們的資訊,你可以查看更新後的 參考文件

取得 Spring 電子報

與 Spring 電子報保持聯繫

訂閱

領先一步

VMware 提供培訓和認證,以加速您的進度。

了解更多

取得支援

Tanzu Spring 在一個簡單的訂閱中提供對 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位檔。

了解更多

即將到來的活動

查看 Spring 社群中所有即將到來的活動。

查看全部