Ⅰ SpringBoot有幾種讀取配置的方式
常見的讀取配置的方式有三種:
第一、@Value註解,比較常用的一種方式。也支持與@propertySource註解何用,指定使用的配置文件
第二、@Configuration註解,讀取配置到類中,批量注入配置屬性
第三、Environment對象,獲取配置文件中所有的屬性的對象
如果你想掌握時下熱門微服務技術棧,跟上時代技術步伐,就去黑馬程序員官網視頻庫看免費視頻。
Ⅱ springboot中獲取apollo或者nacos里的配置文件
常規的,在springboot中一般只需要拿appolo或者nacos里配置的屬性就夠了。
但是也有一些很特殊的場景,要拿到appolo或者nacos里配置的文件,比如有個第三方jar包提供的方法中,要求把properties配置文件路徑傳進去來初始化第三方jar包里需要用到的東西,這時候一般是把properties文件配置到appolo或者nacos里,但是如何直接拿到這個properties文件而不是裡面的屬性值呢?
apollo里直接提供了把配置的相應namespace直接轉換成file的方法:
再把這個content轉換成輸入流就可以用了
如果只是想拿到裡面某個namespace的屬性,則可以:
key為屬性key名,c.getPropertyNames()方法能拿到該namespace下面的所有屬性,返回一個Set<String>集合,再遍歷這個集合就能拿到所有屬性。
nacos跟apollo的處理思路有點不一樣,找了很多資料,貌似沒有找到nacos里直接獲取整個獲取配置文件的方法,後面如果有同學找到了這個方法記得留言提醒我。
nacos在springboot啟動的時候已經把所有配置文件都注入到了spring里。
第一種:可以直接用註解 @Value("${key}")來獲取配置好的屬性值
第二種:在java里獲取:
新建SpringContextUtil實現org.springframework.context.ApplicationContextAware這個介面:
在啟動類用註解導入該類:@Import({SpringContextUtil.class})
利用org.springframework.core.env.Environment類來直接獲取屬性:
如果有這樣一個需求,有個第三方的jar包要求初始化配置好的properties文件,只給了properties文件的路徑傳參,只能用文件路徑的方式初始化這個第三方jar包,那麼我們就必須保證項目里或者其他文件夾有這個properties文件才可以,而這些配置如果經常要變的話,最好也是配置在nacos或者apollo,如此看來,apollo是可以直接把配置的相應namespace直接轉換成file,而nacos大概只能把所有屬性手工生成一個新的properties文件來保存到本地了。
這個生成文件的過程,要在springboot啟動之後立即執行:
那我們就要建一個配置類實現org.springframework.beans.factory.InitializingBean這個介面,重寫afterPropertiesSet()方法:把需要啟動後執行的邏輯放在裡面,下面是一個示例:
把這個類在啟動類里注入:
如此,在啟動的時候就可以在本地生成一個cssconfig.properties文件了。
於是乎就可以類似這樣調用第三方介面(根據第三方jar包來定):
Ⅲ Springboot打成JAR包後讀取外部配置文件
Springboot的application.properties配置文件的載入路徑優先殲念蔽級(從高到低):
當Springboot打成JAR包(不包含配置文件),讀取外部配高薯置文件application.properties時,氏州可以選擇:
Ⅳ springboot配置文件總結
springboot 本身支持多種靈活的配置方式,為開發 springboot 程序帶來了很大的靈活性和擴展性,但是同時由於太靈活,經常會導致明明配置了相關屬性,卻沒有生效。
本文總結了 springboot 配置文件的原理以及多個配置文件生效的順序。
springboot 配置文件支持靈活的路徑,以及靈活的文件名,用一個變數表達式總結如下:
部分源碼如下:
當滿足上述變數表達式的配置文件有多個時,會有一個配置的優先順序。假設
上面每個條件組合起來,則最多有配置文件如下,且順序從上到下:
獲取屬性時,按從上到下的順序遍歷由上述文件生成的屬性資源對象 PropertySource ,如果遇到匹配的key直接返回。
總結一下:就是如果同一個key的屬性只出現一次,則直接取該值即可。如果同一個key的屬性出現多次,則取順序靠前的屬性資源對象。另外其中每個文件都是可選的。
需要注意的一點是:如果在同一個 location 下配置了多個文件名一樣的文件,則只會取一個,比如在 classpath:/ ,有如下兩個文件 application.yml :
則只會根據 classloader 的 classpath 列表,選取第一個出現的文件。因為 springboot 載入配置文件時最底層是使用的下面的方法:
這兩個方法只會獲取 classloader 類的 ucp 屬性裡面第一個匹配到的值。如果對 springboot 自身的機制不滿意,想獲取所有的classpath:/路徑下面的 applicaiton.yml 文件,可以使用下面的方法:
本文總結了 springboot 配置文件的原理以及多個配置文件生效的順序。如果存在增加了配置文件或者在配置文件裡面增加了屬性卻沒有生效,可以參考上面的 springboot 配置文件表達式和配置文件生效順序進行排查。
後面還會有一篇文章討論基於 springboot 配置原理如何實現自定義的配置讀取方式。
Ⅳ springboot讀取.properties配置文件中的map和list類型配置參數
#map 第一種方式
data.person.name=zhangsan
data.person.sex=man
data.person.age=11
data.person.url=xxxxxxxx
#map 第二種方式
data.person[name]=zhangsan
data.person[sex]=man
data.person[age]=11
data.person[url]=xxxxxxxx
#list 第一種方式
data.list[0]=apple0
data.list[1]=apple1
data.list[2]=apple2
#list 第態畢緩二種方帆模式數搭
data.list=apple0,apple1,apple2
Ⅵ SpringBoot 如何優雅讀取配置文件10分鍾教你搞定
很多時候我們需要將一些常用的配置信息比如阿里雲 oss 配置、發送簡訊的相關信息配置等等放到配置文件中。
下面我們來看一下 Spring 為我們提供了哪些方式幫助我們從配置文件中讀取這些配置信息。
application.yml 內容如下:
wuhan2020: 2020年初武漢爆發了新型冠狀病毒,疫情嚴重,但是,我相信一切都會過去!武漢加油!中國加油!my-profile:name: Guide哥email: [email protected]:location: 湖北武漢加油中國加油books: -name: 天才基本法description: 二十二歲的林朝夕在父親確診阿爾茨海默病這天,得知自己暗戀多年的校園男神裴之即將出國深造的消息——對方考取的學校,恰是父親當年為她放棄的那所。 -name: 時間的秩序description: 為什麼我們記得過去,而非未來?時間「流逝」意味著什麼?是我們存在於時間之內,還是時間存在於我們之中?卡洛·羅韋利用詩意的文字,邀請我們思考這一亘古難題——時間的本質。 -name: 了不起的我description: 如何養成一個新習慣?如何讓心智變得更成熟?如何擁有高質量的關系? 如何走出人生的艱難時刻?
1.通過 @value 讀取比較簡單的配置信息
使用 @Value("${property}") 讀取比較簡單的配置信息:
@Value("${wuhan2020}")String wuhan2020;
需要注意的是 @value這種方式是不被推薦的,Spring 比較建議的是下面幾種讀取配置信息的方式。
2.通過@ConfigurationProperties讀取並與 bean 綁定
LibraryProperties 類上加了 @Component 註解,我們可以像使用普通 bean 一樣將其注入到類中使用。
importlombok.Getter;importlombok.Setter;importlombok.ToString;importorg.springframework.boot.context.properties.ConfigurationProperties;importorg.springframework.context.annotation.Configuration;importorg.springframework.stereotype.Component;importjava.util.List;@Component@ConfigurationProperties(prefix ="library")@Setter@Getter@{privateString location;privateList books;@Setter@Getter@ToStringstaticclassBook{ String name; String description; }}
這個時候你就可以像使用普通 bean 一樣,將其注入到類中使用:
packagecn.javaguide.readconfigproperties;importorg.springframework.beans.factory.InitializingBean;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;/** *@authorshuang.kou */@ntsInitializingBean{privatefinalLibraryProperties library;(LibraryProperties library){this.library = library; }publicstaticvoidmain(String[] args){ SpringApplication.run(.class,args); }@(){ System.out.println(library.getLocation()); System.out.println(library.getBooks()); }}
控制台輸出:
湖北武漢加油中國加油[LibraryProperties.Book(name=天才基本法, description........]
3.通過@ConfigurationProperties讀取並校驗
我們先將application.yml修改為如下內容,明顯看出這不是一個正確的 email 格式:
my-profile:name: Guide哥email: koushuangbwcx@
ProfileProperties 類沒有加 @Component 註解。我們在我們要使用ProfileProperties 的地方使用@
EnableConfigurationProperties注冊我們的配置 bean:
importlombok.Getter;importlombok.Setter;importlombok.ToString;importorg.springframework.boot.context.properties.ConfigurationProperties;importorg.springframework.stereotype.Component;importorg.springframework.validation.annotation.Validated;importjavax.validation.constraints.Email;importjavax.validation.constraints.NotEmpty;/***@authorshuang.kou*/@Getter@Setter@ToString@ConfigurationProperties("my-profile")@{@NotEmptyprivateString name;@Email@NotEmptyprivateString email;//配置文件中沒有讀取到的話就用默認值privateBooleanhandsome =Boolean.TRUE;}
具體使用:
packagecn.javaguide.readconfigproperties;importorg.springframework.beans.factory.InitializingBean;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.boot.context.properties.EnableConfigurationProperties;/** *@authorshuang.kou */@SpringBootApplication@EnableConfigurationProperties(ProfileProperties.class){privatefinalProfileProperties profileProperties;(ProfileProperties profileProperties){this.profileProperties = profileProperties; }publicstaticvoidmain(String[] args){ SpringApplication.run(.class,args); }@(){ System.out.println(profileProperties.toString()); }}
因為我們的郵箱格式不正確,所以程序運行的時候就報錯,根本運行不起來,保證了數據類型的安全性:
Binding to target org.springframework.boot.context.properties.bind.BindException:Failedtobindpropertiesunder'my-profile'to cn.javaguide.readconfigproperties.ProfileProperties failed:Property:my-profile.emailValue:koushuangbwcx@Origin:classpathresource[application.yml]:5:10Reason:mustbeawell-formedemailaddress
我們把郵箱測試改為正確的之後再運行,控制台就能成功列印出讀取到的信息:
ProfileProperties(name=Guide哥, [email protected], handsome=true)
4.@PropertySource讀取指定 properties 文件
importlombok.Getter;importlombok.Setter;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.context.annotation.PropertySource;importorg.springframework.stereotype.Component;@Component@PropertySource("classpath:website.properties")@Getter@SetterclassWebSite{@Value("${url}")privateString url;}
使用:
@Autowiredprivate WebSite webSite;System.out.println(webSite.getUrl());//https://javaguide.cn/
5.題外話:Spring 載入配置文件的優先順序
Spring 讀取配置文件也是有優先順序的,直接上圖:
原文鏈接:https://www.toutiao.com/a6791445278911103500/?log_from=7f5fb8f9b4b47_1640606437752
Ⅶ SpringBoot 配置文件詳解(告別XML)
快速學會和掌握 SpringBoot 的 核心配置文件的使用。
SpringBoot 提供了豐富的 外部配置 ,常見的有:
其中核心配置文件我們並不陌生,主要以Key-Value的形式進行配置,其中屬性Key主要分為兩種:
在 application.properties 添加配置如下:
① 添加數據源信息
在 application.propertis 添加配置如下:
① 添加認證信息,其中 socks.indentity.* 是自定義的屬性前綴。
② 添加隨機值,其中spring.test.* 是自定義的屬性前綴。
使用方法: @ConfigurationProperties(prefix = "spring.datasource")
使用說明:提供 Setter方法 和 標記組件 Component
如何驗證是否成功讀取配置?答:這里可以簡單做個驗證,注入 MyDataSource ,使用 Debug 模式可以看到如下信息:
使用方法: @Value("spring.datasource.*")
使用說明:提供 Setter方法 和 標記組件 Component
注意事項:@Value不支持注入靜態變數,可間接通過Setter注入來實現。
關於兩者的簡單功能對比:
顯然,前者支持松綁定的特性更強大,所以在實際開發中建議使用@ConfigurationProperties來讀取自定義屬性。
SpringBoot 默認會載入這些路徑載入核心配置文件,按優先順序從高到低進行排列:具體規則詳見 ConfigFileApplicationListener
如果存在多個配置文件,則嚴格按照優先順序進行覆蓋,最高者勝出:
舉個簡單的例子,例如再上述位置都有一個application.properties ,並且每個文件都寫入了server.port=xx (xx分別是9001,9002,9003,9004),在啟動成功之後,最終應用的埠為:9004。圖例:
如果想修改默認的載入路徑 或者 調改默認的配置文件名,我們可以藉助命令行參數進行指定,例如:
YAML是JSON的一個超集,是一種可輕松定義層次結構的數據格式。
答: 因為配置文件這東西,結構化越早接觸越規范越好。這里推薦閱讀阮一峰老師寫的 YAML語言教程 ,寫的很簡單明了。
引入依賴: 在POM文件引入 snakeyaml 的依賴。
使用說明: 直接在類路徑添加 application.yml 即可。
例如下面這兩段配置是完全等價的:
① 在 application.yml 配置數據源:
② 在 application.properties 配置數據源:
在項目的實際開發中,我們往往需要根據不同的環境來載入不同的配置文件。例如生產環境,測試環境和開發環境等。此時,我們可以藉助 Profiles 來指定載入哪些配置文件。例如:
溫馨提示:如果spring.profiles.active指定了多個配置文件,則按順序載入,其中最後的優先順序最高,也就是最後的會覆蓋前者。
使用方法:
使用Maven插件打包好項目,然後在當前路徑,執行DOS命令: java -jar demo.jar --server.port=8081 ,在控制台可看到應用埠變成了8081。
實現原理:
默認情況下,SpringBoot會將這些命令行參數轉化成一個 Property ,並將其添加到 Environment 上下文。
溫馨提示:
由於命令行參數優先順序非常之高,基本高於所有常見的外部配置,所以使用的時候要謹慎。詳見 PropertySource 執行順序 。
關閉方法:
如果想禁用命令行屬性,可以設置如下操作:springApplication.setAddCommandLineProperties(false)
Ⅷ Kotlin + Spring Boot 使用@Value讀取配置文件
TL;DR
在做的一個項目遇到這個問題凳掘,需要把server.host存在application.properties裡面,但是在取value 的時候遇到了問題,總是提示 」lateinit property *** has not been initialized「,找遍了和so 都沒有太好的答案,多方參考以後終於才解決這個小問題。
這個問題猜返的存在是因為在spring 跑到@service class的時候,我們還沒有取到配置文件裡面的value, 所以導致了穗粗飢spring 認為這個value variable沒有initialize。
解決方案就是把你要取的value放到class的constructor裡面去,下面提供一個簡單的example。
-application.properties
-Service.kt
Reference:
Kotlin Doc - Constructor
Another code example
Ⅸ Springboot 讀取配置文件原理
Springboot 讀取配置文件(application.yaml, application.properties)的過程發生在SpringApplication#prepareEnvironment() 階段,而prepareEnvironment又屬於整個Springboot 應用啟動的非常前置階段,因為Environment的准備是後續bean創建的基礎。讓我們來一探啟動是的詳細code。除去StopWatch這些code,可以發現prepareEnvironment 發生在SpringApplication#run 這在整個應用啟動的多步實質性操作中幾乎是第一步。
而prepareEnvironment中最重要的是通過觸發listener(EventPublishingRunListener)來通過#multicastEvent發出。
而#multicastEvent的實現其實也很簡單,找到相關的監聽的listener,然後一個個的調用他們的Listener#onApplicationEvent(event)方法,而這其中就包括了處理configuration文件的listener。
在Springboot 2.4.0 之前這個處理configuration 文件的lister是ConfigFileApplicationListener,在2.4.0之後,處理configuration 文件的lister是,並且對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")。 如果我的應用中存在的某個自定義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了,取而代之的是,通過調用來完成configuration載入。
.java
.java
只是老老實實的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人解決一切問題的不變的方法論。