序言
在很久以前,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中進行智能提示。
不然在沒有源碼的情況下,根本不知道“配置屬性”類的結構以及屬性名和屬性類型。
>>> 熱門文章集錦 <<<
爸爸又給Spring MVC生了個弟弟叫Spring WebFlux
【面試】吃透了這些Redis知識點,面試官一定覺得你很NB(干貨 | 建議珍藏)
【面試】如果你這樣回答“什么是線程安全”,面試官都會對你刮目相看(建議珍藏)
【面試】迄今為止把同步/異步/阻塞/非阻塞/BIO/NIO/AIO講的這么清楚的好文章(快快珍藏)
【面試】一篇文章幫你徹底搞清楚“I/O多路復用”和“異步I/O”的前世今生(深度好文,建議珍藏)
>>> 品Spring系列文章 <<<
品Spring:SpringBoot和Spring到底有沒有本質的不同?
品Spring:SpringBoot輕松取勝bean定義注冊的“第一階段”
品Spring:SpringBoot發起bean定義注冊的“二次攻堅戰”
品Spring:注解之王@Configuration和它的一眾“小弟們”
品Spring:對@PostConstruct和@PreDestroy注解的處理方法
品Spring:對@Autowired和@Value注解的處理方法
品Spring:真沒想到,三十步才能完成一個bean實例的創建
品Spring:關於@Scheduled定時任務的思考與探索,結果尷尬了
作者是工作超過10年的碼農,現在任架構師。喜歡研究技術,崇尚簡單快樂。追求以通俗易懂的語言解說技術,希望所有的讀者都能看懂並記住。下面是公眾號的二維碼,歡迎關注!