【玩轉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框架內部的源碼都是這樣用的。

既然“配置屬性”類最后注冊了bean定義,那可不可用常規的bean定義注冊方式呢?

試試就知道了,如下圖20:

 

可以看出,這里使用的@Component注解。

這樣的話,就不再需要另一個注解引入了,把它注釋掉,如下圖21:

 

其它的都保持不變。然后進行測試,發現完全可以。

不過還是推薦使用SpringBoot指定的方式,因為SpringBoot可以對這種方式進行特殊的優化處理。

比如使用@Validated進行驗證。還可以把@NestedConfigurationProperty注解標到嵌套的字段上。

這樣不會影響屬性值的綁定,但是可以讓SpringBoot給你在IDE中進行智能提示。

不然在沒有源碼的情況下,根本不知道“配置屬性”類的結構以及屬性名和屬性類型。

>>> 熱門文章集錦 <<<

 

畢業10年,我有話說

【面試】我是如何面試別人List相關知識的,深度有點長文

我是如何在畢業不久只用1年就升為開發組長的

爸爸又給Spring MVC生了個弟弟叫Spring WebFlux

【面試】我是如何在面試別人Spring事務時“套路”對方的

【面試】Spring事務面試考點吐血整理(建議珍藏)

【面試】我是如何在面試別人Redis相關知識時“軟懟”他的

【面試】吃透了這些Redis知識點,面試官一定覺得你很NB(干貨 | 建議珍藏)

【面試】如果你這樣回答“什么是線程安全”,面試官都會對你刮目相看(建議珍藏)

【面試】迄今為止把同步/異步/阻塞/非阻塞/BIO/NIO/AIO講的這么清楚的好文章(快快珍藏)

【面試】一篇文章幫你徹底搞清楚“I/O多路復用”和“異步I/O”的前世今生(深度好文,建議珍藏)

【面試】如果把線程當作一個人來對待,所有問題都瞬間明白了

Java多線程通關———基礎知識挑戰

品Spring:帝國的基石

 

>>> 品Spring系列文章 <<<

 

品Spring:帝國的基石

品Spring:bean定義上梁山

品Spring:實現bean定義時采用的“先進生產力”

品Spring:注解終於“成功上位”

品Spring:能工巧匠們對注解的“加持”

品Spring:SpringBoot和Spring到底有沒有本質的不同?

品Spring:負責bean定義注冊的兩個“排頭兵”

品Spring:SpringBoot輕松取勝bean定義注冊的“第一階段”

品Spring:SpringBoot發起bean定義注冊的“二次攻堅戰”

品Spring:注解之王@Configuration和它的一眾“小弟們”

品Spring:bean工廠后處理器的調用規則

品Spring:詳細解說bean后處理器

品Spring:對@PostConstruct和@PreDestroy注解的處理方法

品Spring:對@Resource注解的處理方法

品Spring:對@Autowired和@Value注解的處理方法

品Spring:真沒想到,三十步才能完成一個bean實例的創建

品Spring:關於@Scheduled定時任務的思考與探索,結果尷尬了

 

作者是工作超過10年的碼農,現在任架構師。喜歡研究技術,崇尚簡單快樂。追求以通俗易懂的語言解說技術,希望所有的讀者都能看懂並記住。下面是公眾號的二維碼,歡迎關注!


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM