當前位置:編程學習大全網 - 源碼下載 - Springboot 讀取配置文件原理

Springboot 讀取配置文件原理

Springboot 讀取配置文件(application.yaml, application.properties)的過程發生在SpringApplication#prepareEnvironment() 階段,而prepareEnvironment又屬於整個Springboot 應用啟動的非常前置階段,因為Environment的準備是後續bean創建的基礎。讓我們來壹探啟動是的詳細code。除去StopWatch這些code,可以發現prepareEnvironment 發生在SpringApplication#run 這在整個應用啟動的多步實質性操作中幾乎是第壹步。

而prepareEnvironment中最重要的是通過觸發listener(EventPublishingRunListener)來通過SimpleApplicationEventMulticaster#multicastEvent發出ApplicationEnvironmentPreparedEvent。

而SimpleApplicationEventMulticaster#multicastEvent的實現其實也很簡單,找到相關的監聽ApplicationEnvironmentPreparedEvent的listener,然後壹個個的調用他們的Listener#onApplicationEvent(event)方法,而這其中就包括了處理configuration文件的listener。

在Springboot 2.4.0 之前這個處理configuration 文件的lister是ConfigFileApplicationListener,在2.4.0之後,處理configuration 文件的lister是EnvironmentPostProcessorApplicationListener,並且對configuration文件的加載做了較大的改變,導致壹些行為可能出現了變化,這也就是下面要詳細講的內容。

Springboot 2.4.0之後,configuration 文件的load順序按照優先級是如下順序(序號大的會被小的覆蓋):

和之前版本比較,整體的屬性加載順序並無調整,只有Application properties(14,15)這裏有順序的調整,具體調整為:

如果存在多個active的profiles,例如[Test, Dev], 那麽對於同時存在兩個profile 配置文件中的配置,後面的profile裏的配置(Dev)會覆蓋前面profile(Test)裏配置的值。

前面講了這麽多,終於要引出Springboot 2.4之後配置文件加載的行為變化了。

考慮這樣的情況,如果我想在跑Springboot test的時候指定特定的profile,那麽可以在Test class中加入@ActiveProfile("Test")。 如果我的應用中存在ApplicationEnvironmentPreparedEvent的某個自定義listener中,會根據當前environment 設置profile,如env.addActiveProfile("Dev")。

當前就會有兩個active profile,由於springboot-test會在調用application#run 前利用DefaultActiveProfilesResolver把@ActiveProfile註解定義的profile(Test)先加入了active的profile,等test run的時候 env.addActiveProfile("Dev") 又會把"Dev"也作為active profile 加入,這時候當前的active profile便為["Test", "Dev"]。

據上面介紹,後面的profile(Dev)對應的configuration 會覆蓋前面的(Test)。可Springboot 2.4.0之前的版本為我們做了調整,讓Test class中@ActiveProfile內定義的profile所對應的配置文件成為最高優先級。

剛才提到在Springboot 2.4.0 之前這個處理configuration 文件的lister是ConfigFileApplicationListener,我們

來看看ConfigFileApplicationListener的相關code。

查看initializeProfiles(),發現此時對profile的順序做了調整,將activatedViaProperty (Test) 放在最後add,於是profile的順序就變成了[Dev, Test]。

在profiles.poll()時原本profile的順序已經倒了過來,已經變為[Dev, Test], 在load()方法中由於後置的Test profile,application-Test.yaml中的值最終生效了。

可是到了Springboot2.4.0之後,ConfigFileApplicationListener被deprecated了,取而代之的是EnvironmentPostProcessorApplicationListener,EnvironmentPostProcessorApplicationListener通過調用ConfigDataEnvironmentPostProcessor來完成configuration加載。

EnvironmentPostProcessorApplicationListener.java

ConfigDataEnvironmentPostProcessor.java

ConfigDataEnvironmentPostProcessor只是老老實實的set了active profile,並沒有調換profile的順序。最後調用定義在spring.factories中的resource loader class來load 配置文件。

YamlPropertySourceLoader.java

插壹句,Springboot為我們提供了很好的yaml文件parse的code,當妳需要解析yaml文件時不妨直接參考Springboot的YamlPropertySourceLoader

這樣壹旦應用升級到Springboot 2.4.0之後相同的test code會使用application-Dev.yaml中配置的值,造成了test結果的改變。

如果要解決這個問題,根據上面介紹的配置文件優先級順序,可以在@SpringbootTest中設置properties 來作為最終的配置覆蓋當前profile對應的配置。

了解壹個框架很不容易,壹個小小的變化都有可能造成應用的行為變化,唯有刨根問底,不斷總結才是framework人解決壹切問題的不變的方法論。

  • 上一篇:dll 是什麽文件的擴展名,用什麽軟件編寫
  • 下一篇:我是網管 想在遊戲菜單加新網遊 該怎麽做?
  • copyright 2024編程學習大全網