Spring Boot 属性配置你所不知道的细节
今天我們要聊的這個(gè)問題,可能工作5年的資深程序員也不一定搞得很清楚,但是我敢保證在開發(fā) Web 應(yīng)用過程中大家都遇到過。
這個(gè)問題就是: Spring Boot 應(yīng)用程序讀取配置屬性時(shí),不同配置源的優(yōu)先級(jí)是個(gè)啥情況?
那如果你對(duì)這個(gè)問題沒啥概念,我給大家說幾個(gè)場(chǎng)景,你肯定就明白了?
應(yīng)用程序的數(shù)據(jù)庫配置,我們一般都是通過配置文件配置的?不會(huì)有人直接硬編碼寫的吧;
應(yīng)用開發(fā)中往往都需要加一些開關(guān)來控制業(yè)務(wù)邏輯,比如新功能灰度之類的場(chǎng)景;
開發(fā)、測(cè)試、生產(chǎn)環(huán)境需要不同的值,這種變量一般也都是通過外置配置來讀取的,不會(huì)直接寫死的;
我想上面這幾種場(chǎng)景,搞過 Java 開發(fā)的總歸會(huì)遇到的,今天我們要聊的就是這些外置的配置屬性,配置在不同的地方,如果屬性名一樣的情況下,到底誰的優(yōu)先級(jí)高?也可以說配置在高優(yōu)先級(jí)地方的屬性值會(huì)覆蓋低優(yōu)先級(jí)位置的同名屬性值。
說實(shí)話,這個(gè)問題我身邊很多工作了多年的資深開發(fā)都沒有搞明白,不過這個(gè)并不影響他們開發(fā),大不了調(diào)試一波嘛,就是多費(fèi)點(diǎn)時(shí)間。但是也有特別騷的情況,他們也頭大。
比如生產(chǎn)環(huán)境莫名其妙的出了問題,排查是因?yàn)橐粋€(gè)配置屬性值不對(duì)導(dǎo)致的,但是測(cè)試環(huán)境看了沒問題,然后項(xiàng)目中的配置文件配置的也沒問題,這種就很煩人了。
排查到最后一般就會(huì)發(fā)現(xiàn):生產(chǎn)環(huán)境的啟動(dòng)命令加了命令行參數(shù)或者 JVM 系統(tǒng)屬性,比這還騷的就是配到了系統(tǒng)的環(huán)境變量里面。。
那今天這個(gè)問題搞懂了,就有以下幾個(gè)好處:
可以幫助你高效的開發(fā)出符合預(yù)期的應(yīng)用程序;
在排查一些老代碼導(dǎo)致的異常時(shí),多一個(gè)排查思路,看看是否是不同環(huán)境的屬性配置不同(經(jīng)常有一些老項(xiàng)目的屬性值是配置在環(huán)境變量里,覆蓋了代碼里面的屬性配置);
提高開發(fā)效率(在不改項(xiàng)目配置的情況下,通過高優(yōu)先級(jí)的屬性源覆蓋對(duì)應(yīng)的屬性)
Spring Boot 常用的屬性源
下面列舉出我們平時(shí)常用的一些配置屬性源:
這些屬性源其實(shí)我已經(jīng)按照優(yōu)先級(jí)從高到低的順序排列了,也就是說命令行參數(shù)的優(yōu)先級(jí)最高,其次是 JVM 系統(tǒng)屬性,默認(rèn)屬性優(yōu)先級(jí)最低,同名屬性將會(huì)遵循高優(yōu)先級(jí)覆蓋掉低優(yōu)先級(jí)。
這其實(shí)就是本文的最終結(jié)論了,后面就是介紹各種屬性源如何設(shè)置,進(jìn)行實(shí)操驗(yàn)證了。你如果不想往后看了,直接收藏這張圖片也是可以的哦~
這些屬性配置的方法部分小伙伴可能沒有用過,接下來我們用一個(gè)例子來實(shí)戰(zhàn)演示下,也推薦你動(dòng)手實(shí)踐,試試結(jié)論是否正確,這樣理解記憶會(huì)更加深刻。
驗(yàn)證配置屬性的優(yōu)先級(jí)
為了能夠清晰高效的達(dá)到我們驗(yàn)證各個(gè)屬性源配置屬性優(yōu)先級(jí)的目的,這里的思路就是:先在低優(yōu)先級(jí)的屬性源配置,然后配置高優(yōu)先級(jí),如果覆蓋了就說明我們的結(jié)論沒毛病。
首先我們使用 Spring Boot 快速寫一個(gè)簡(jiǎn)單的 Web 接口,然后直接返回配置的屬性名:
@RestController public?class?ReadingListController?{//?獲取屬性配置的類@Resourceprivate?MyProperties?myProperties;@GetMapping("/getMaxValue")public?String?getProperties?()?{return?"配置的屬性值?=?"?+?myProperties.getMaxValue();} }上面我們使用了一個(gè)專門用來獲取配置屬性的 Bean,不建議直接在 Controller 引用屬性,這個(gè)大家平時(shí)在開發(fā)中也要注意下:
@Component @ConfigurationProperties(prefix=?"my"?) @Data public?class?MyProperties?{//?默認(rèn)屬性值private?int?maxValue=?0;}那上面的代碼就是我們測(cè)試所需要的全部代碼了,接下來我們從最低優(yōu)先級(jí)的屬性源開始配置。
默認(rèn)屬性
這個(gè)不用多說,就是直接在 Java 代碼中聲明變量時(shí)賦予的值;
啟動(dòng)應(yīng)用程序后,訪問我們的測(cè)試接口:http://localhost:8000/getMaxValue
通過 @PropertySource 標(biāo)注的屬性源
這種屬性配置的方法我們一般也經(jīng)常用,就是自定義一個(gè)配置文件,然后用 @PropertySource 注解來指定加載。
上面的代碼,就會(huì)加載我們定義在 classpath 路徑下的 my.properties 文件了。我們?cè)谧远x的屬性配置文件 my.properties 中添加配置屬性:
my.maxValue=1然后重啟應(yīng)用,訪問我們的測(cè)試接口,得到的輸出如下:
這就證明了 @PropertySource 屬性源配置覆蓋了默認(rèn)配置。
application.properties配置文件
Spring Boot 應(yīng)用程序,默認(rèn)會(huì)加載 classpath 路徑下 application.properties 和 application.yml 文件中配置的屬性。這也是我們開發(fā)時(shí)最常用的屬性配置源了。
在重啟應(yīng)用,訪問我們的測(cè)試接口,就會(huì)得到結(jié)果值 2 了。說明應(yīng)用內(nèi)的 application.properties 文件中配置的屬性優(yōu)先級(jí)高于 @PropertySource 指定的自定義配置文件。
這里需要注意,如果 classpath 路徑下同時(shí)存在 application.yml 和 application.properties 文件,那么 application.yml 文件中的屬性優(yōu)先級(jí)高于 application.properties,這一點(diǎn)大家也可以自己測(cè)試下。
操作系統(tǒng)環(huán)境變量
這是一種騷操作了,在不同的環(huán)境設(shè)置了不同的操作系統(tǒng)環(huán)境變量,任你看代碼找破天也是一頭霧水。所以下次出現(xiàn)不同環(huán)境配置屬性值不符合預(yù)期的場(chǎng)景,操作系統(tǒng)環(huán)境變量記著檢查下。
這里我使用的 zsh,可以使用 export 來設(shè)置臨時(shí)的操作系統(tǒng)環(huán)境變量,當(dāng)然 bash 也可以這樣配置。
export?my_maxvalue=3?細(xì)心的同學(xué)發(fā)現(xiàn)了,變量的命令我使用了下劃線而不是點(diǎn),這是因?yàn)椴僮飨到y(tǒng)對(duì)變量名稱的要求。
然后我們將應(yīng)用打包,我這里使用的 gradle 來構(gòu)建項(xiàng)目,只需要執(zhí)行:gradle build , Spring Boot ?提供的 gradle 插件就會(huì)幫我們將所有需要的依賴打包到一起,得到一個(gè)可執(zhí)行的 jar 包。
然后我們啟動(dòng)應(yīng)用程序:java -jar build/libs/spring-road02-0.0.1-SNAPSHOT.jar
訪問測(cè)試接口得到的值就是3了。
結(jié)論證明:操作系統(tǒng)環(huán)境變量配置的屬性優(yōu)先級(jí)又高于上面我們所列舉的。
JVM系統(tǒng)屬性
這也是生產(chǎn)環(huán)境使用最多的一種差異化屬性設(shè)置方式,在應(yīng)用程序的啟動(dòng)腳本命令中指定屬性值,好處就是其他人不能隨意修改,一般只能運(yùn)維人員來編寫的。常見于配置一些影響應(yīng)用程序運(yùn)行穩(wěn)定性的參數(shù),比如內(nèi)存分配、GC參數(shù)等的配置。
還是使用上面我們打好的 jar 包,在運(yùn)行時(shí)增加 JVM 系統(tǒng)屬性即可:
java?-Dmy.maxvalue=4?-jar?build/libs/spring-road02-0.0.1-SNAPSHOT.jar然后訪問測(cè)試接口得到的值就變?yōu)榱?。
命令行屬性配置
這個(gè)和 JVM 系統(tǒng)屬性配置的使用場(chǎng)景差不多,只不過設(shè)置方式有點(diǎn)區(qū)別,直接看下命令行啟動(dòng)配置就明白了:
java?-Dmy.maxvalue=4?-jar?build/libs/spring-road02-0.0.1-SNAPSHOT.jar?--my.maxvalue=5啟動(dòng)后,我們繼續(xù)訪問測(cè)試接口看看結(jié)果:
結(jié)果證明,命令參數(shù)的優(yōu)先級(jí)比 JVM 系統(tǒng)屬性優(yōu)先級(jí)高,會(huì)將其覆蓋。
總結(jié)
通過今天的實(shí)踐學(xué)習(xí),大家應(yīng)該對(duì) Spring Boot 屬性配置常見的幾種來源有了更加清晰的認(rèn)識(shí),并且通過實(shí)驗(yàn)測(cè)試了它們具體的優(yōu)先級(jí)。我們?cè)賮韰R總整理下:
按照優(yōu)先級(jí)的高低從上往下排列,也就是說命令行參數(shù)配置的屬性優(yōu)先級(jí)最高,會(huì)覆蓋其它屬性源的配置,以此類推,記不住的小伙伴可以收藏下,以備不時(shí)之需。
今天就先聊到這里,更多關(guān)于 Spring 相關(guān)的內(nèi)容,也在持續(xù)更新中,敬請(qǐng)關(guān)注!
有道無術(shù),術(shù)可成;有術(shù)無道,止于術(shù)
歡迎大家關(guān)注Java之道公眾號(hào)
好文章,我在看??
新人創(chuàng)作打卡挑戰(zhàn)賽發(fā)博客就能抽獎(jiǎng)!定制產(chǎn)品紅包拿不停!總結(jié)
以上是生活随笔為你收集整理的Spring Boot 属性配置你所不知道的细节的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vue项目 预览照片的插件 v-view
- 下一篇: JSON.stringify()还可以这