【玩轉SpringBoot】配置檔案yml的正確開啟姿勢
序言
在很久以前,Spring的配置檔案是基於XML的。它的名字就是applicationContext.xml,沒錯,就只有這一個xml檔案。
它裡面配置了所有的東西。但是資料庫資訊通常會單獨拿出來,放入一個properties檔案,通常叫db.properties。
後來覺著一個xml裡的東西實在太多了,就按功能拆分成幾個獨立的xml。
spring-dao.xml是dao層,spring-service.xml是service層,spring-tx.xml是事務相關,dispatcher-servlet.xml是web相關。
這麼多的xml怎麼辦呢?很簡單,就是在applicationContext.xml裡都引用它們即可。
隨著JDK在1.5加入了對註解的支援,Spring也慢慢的向註解轉化。直至後來一個xml都不剩,全部變為註解,連web.xml都沒有了。
是xml不行了,還是註解太牛X了,其實它們是等價的,連官網上都說它們一摸一樣,故而不做推薦,讓使用者根據實際情況自己選擇。
不過,最終歷史還是拋棄了XML,肯定是多方面的原因,可能如下:
1)人們厭倦了XML,出現審美疲勞
2)試用了註解很爽,一發不可收拾
3)註解代表著先進的生產力,極大提升了效率
4)XML拖沓累贅,註解清爽乾脆
5)大家都覺得使用註解比使用XML更牛B。
於是乎,一個輝煌的新時代碾壓了一個曾經輝煌的曾經的新時代。
呵呵,歷史是什麼,就是個車輪。一切皆可碾壓。
總之,既有實際實踐問題,又有思想意識問題,說不清,道不明。
隨著SpringBoot的橫空出世,配置檔案的概念又發了變化。
SpringBoot強調自動配置(也叫自動裝配),所以配置對它來說很重要。
配置檔案屬於配置的一部分,自然也變得非常重要,於是yml就應勢站了起來。
yml從未像現在這樣流行,成了新時代的網紅。
yml配置檔案的格式
每種新事物的流行,總會有它比舊事物更好的地方。
作為Java界配置檔案鼻祖,非properties檔案莫屬,它裡面的格式就不用再舉例了吧。
它是一維非結構化的,一行一個,寫多了容易亂。
而yml檔案是二維結構化的,有嚴格的縮排,結果就是層次分明,非常清晰。
而且,常用的配置都能得到支援,這就是它的優勢,所以就流行起來了。
一、List配置格式,如下圖01:
二、Map配置格式,如下圖02:
三、List套List格式,如下圖03:
四、List套Map格式,如下圖04:
五、Map套Map格式,如下圖05:
六、Map套List格式,如下圖06:
雖然有些巢狀可能並不適用,這裡只是說明yml支援這樣的巢狀,如果願意的話,巢狀層次還可以更深。
yml配置檔案內容的儲存
大家都知道SpringBoot是由Spring發展而來的,Spring裡是有Environment這個概念的。
所有的環境變數、系統屬性、配置檔案內容都會放進去。
通常的配置項都是一些key=value,就和properties檔案是一樣的。所以Environment底層也是這樣實現的。
但到了SpringBoot中,配置檔案變為yml了,是二維結構化的,根本沒有辦法直接用key=value這種形式表示。
但是,yml配置檔案的內容還必須要放入到Environment中去。那怎麼辦呢?看來二者必須要修改其一了。
由於Spring已經很多年了,它裡面的很多概念都已經固化下來了,包括Environment內部的結構與實現。
因此,最終選擇yml去適配Environment,把二維結構化變為一維非結構化,即把有層次的變為簡單的key=value形式。
這在程式設計裡有一個專門的術語,叫扁平化。其實人員管理裡面也有扁平化。
具體規則也非常簡單,把父子關係用點號(.)表示,把列表索引用中括號([])表示。
把剛剛的配置內容輸出來看看,如下圖070809:
這樣就完成了扁平化,就可以存入到Environment中去了。
等號(=)前面的就是key,後面的就是值。
直接粗暴的使用yml配置檔案內容
由於yml配置檔案內容最終會進入Environment中,所以就等於直接粗暴的從Environment中讀取值。
此時,key必須要寫成上面那樣子,否則取不到值。
一、直接從Environment中讀取,如下圖10:
結果輸出如下圖11:
二、使用@Value註解,如下圖12:
結果輸出如下圖13:
這就是簡單粗暴的方式,除了看上去不美觀之外,還把yml的結構化特徵給丟失了。
其實,還有一個比較嚴重的問題,就是隻能獲取到最終key對應的單個值,如果想獲取一個List或Map作為返回值,是不行的。
優雅的使用yml配置檔案內容
key=value這種形式其實就是個Map,而Map其實和Java Bean差的並不多,只不過Bean中是屬性名和屬性值罷了。
Map套Map就等於Bean套Bean,這樣無論結構形式還是語義表達都能很完美的對映過來。
且Bean是強型別的,屬性名和屬性型別一目瞭然,比Map強多了。
所以yml配置檔案裡的內容可以對映為Java裡的Bean,這就是SpringBoot推薦的優雅的使用方式。
這裡的核心問題就是,yml裡的配置項要和Bean中的屬性名稱和型別對應好,不然會出問題。
下面請看一個示例,自己瞎編了一個游泳比賽的得分和獎品的配置。
含有一等獎、二等獎、三等獎的得分割槽間,和它們分別對應的獎品名稱和數量。
如下圖14:
可以看到scores對應的是一個列表,它有三個元素,每個元素都有level、lowBound、highBound三個屬性。
awards對應一個Map,它有三個key,分別是level1、level2、level3,每個key對應的值又是一個列表。
且列表都含有兩個元素,且每個元素都有name、count兩個屬性。
如果這個明白了,下面請看它對應的Bean,如下圖15:
Score和Award是兩個靜態內部類。一個有三個屬性,一個有兩個屬性。
ScoreProperties類中有兩個屬性,一個是scores,型別是List<Score>。
一個是awards,型別是Map<String, List<Award>>。
可以看出,它們和yml的結構是完全吻合的。沒有難度吧。
為了使它用起來更優雅,SpringBoot定義了兩個註解來助它一臂之力。
首先,在Bean上標上@ConfigurationProperties,表示它是一個“配置屬性”。
如下圖16:
其次,在另一個類上使用@EnableConfigurationProperties註解將其引入。
如下圖17:
經過這兩步,這個“配置屬性”類就已經被註冊到容器裡了,就變成一個普通的bean了。
這樣就可以把它注入到需要的地方,如下圖18:
使用的是構造方法注入,並輸出一下它的值,看看和yml中配置的是否一樣。
結果如下圖19:
可以看到,完全沒有問題。這就是SpringBoot推薦的方式。
SpringBoot框架內部的原始碼都是這樣用的。
既然“