【玩轉SpringBoot】用好條件相關注解,開啟自動配置之門



自動配置隱含兩層含義,要搞清楚



上帝讓程序員的發量減少,是為了讓他變得更聰明,如果有一天聰明到了極點,那就是絕頂聰明。

據說在大腦高速運轉下,這樣更有利於散熱,不至於核心溫度過高而產生告警。

聰明的大腦是用來思考的,現在就來深入思考和分析下自動配置。

自動配置包含兩層意思,一個是配置,一個是自動。這不廢話嘛。

配置存在的一個前提是,要有選擇才行,如果沒得選擇,就不用談配置了。

比如十幾年前讀大學時,無論是回家還是去學校,都只能坐最便宜的硬座。因為沒得選擇。

現在情況就不一樣了,高鐵、動車、飛機都可以了。有了選擇,就可以談配置了。

所以配置就是在一些可選項里做出選擇,既然是選擇,就需要有選擇的依據/理由。

如果距離不太遠的話,選擇高鐵,這樣在花費的時間和金錢上是相對均衡的。

如果此時想稍微省點錢的話,選擇動車,不過花的時間稍多些。也算一種取舍吧。

如果距離太遠的話,選擇飛機,這樣時間和金錢上才是最均衡的。

這些列舉出來的影響選擇的因素,其實就是“條件”。因此,配置就是根據條件做出選擇。

那自動的意思就是,使用工具或一套程序根據條件做出選擇,最后只把結果告訴我們即可。

就是說,我們不參與選擇的過程,我們只需提供一些和“條件”相關的信息即可。


Spring的風格,萬物皆可注解


通過上一小節,我們成功的把自動配置轉化為條件和工具。

回到程序里,條件指的是什么?如果不知道的話,那條件語句指的是什么?

就是if...else,要根據條件做出判斷,所以條件就是某種形式的程序代碼。

那工具呢?就是一些常用代碼或算法的集合嘛。也是某種形式的程序代碼。

條件和工具已經被成功的轉化為了程序代碼,現在來看,自動配置就等於程序代碼。

關鍵是這個程序代碼是讓我們來寫嗎?如果是的話,那可就產生悖論了。

因為配置通常意味着不寫代碼,如果還要寫代碼的話,那就不叫配置了,叫搞笑了。

因此,條件和工具的程序代碼,SpringBoot都寫好了,並通過注解進行了封裝。

最后把這些注解暴露出來,供用戶使用,這就是條件注解的由來。

用戶可以通過設置注解屬性把“條件”相關信息傳遞進去,讓底層的“工具”進行判斷和選擇。

最終,不同的條件產生了不同的行為,達到了自動配置的目的。


官方提供的常用條件注解


因為Spring的核心是基於bean的,所以這些條件注解主要是影響bean的注冊。

因為注冊的bean不同了,最后對外呈現的行為就不同了。不就是自動配置了。

一、最常用的應該是@Profile注解了

根據不同的環境可以注冊不同的bean,如下圖01:


首先,不激活任何環境,執行一下,結果如下圖02:


可以看到,沒有激活任何環境,所以默認是default。因此Default類就被注冊了。

然后,激活一下prod環境,在IDE里設置一下,如下圖03:


再次運行一下,結果如下圖04:


可以看到,prod環境被激活了,所以Prod類就被注冊了。

SpringBoot內置了一些注解,如下圖05:


我們關注一些常用的就可以了。

二、@ConditionalOnProperty注解

這個注解用於檢測Environment中的指定屬性是否存在或等於某個指定的值。

如下圖06:


如havingValue屬性沒有指定的話,那么只要實際屬性值不等於false,都算匹配成功。如果指定了,那就必須要一樣才行。

matchIfMissing屬性就是說,如果沒有發現這個屬性,算不算匹配上,設置為true就算,false就不算,默認為不算。

請看配置文件,如下圖07:


很明顯,這是可以匹配上的,運行一下,結果如下圖08:


可以看到,對應的類被注冊了bean定義。

三、@ConditionalOnClass注解

這個注解用於檢測類路徑里是否包含某個類,其實就是確定是否引入了指定的依賴。

如下圖09:


因為我用的JDK1.8,肯定有這個類,所以會匹配上,結果如下圖10:


:@ConditionalOnMissingClass注解原理一樣,只不過是否定性的匹配而已。

四、@ConditionalOnBean注解

這個注解用於檢測容器中是否包含指定的bean。如下圖11:


除了可以用Class<?>指定bean外,還可以使用類的全名稱,還可以使用bean名稱(即beanName)。

還可以使用注解指定是否包含標有該注解的bean。

示例中是通過Class<?>來指定的,而且指定的是之前注冊過的bean,所以一定能匹配上。

執行結果如下圖12:


:@ConditionalOnMissingBean注解原理一樣,只不過是否定性的匹配而已。

五、@ConditionalOnSingleCandidate注解

這個注解用於檢測容器中能夠匹配上的候選bean是否只有一個。

只有一個是什么意思呢?就是某個類只注冊了一次,這時就是只有一個。比如Boss類。

但是員工可以有多個,所以就會有多個Staff類被注冊。此時就不滿足條件了。

如果此時還想滿足的話,就必須在其中一個Staff類注冊時標上@Primary注解。

如下圖13:


因為我們指定的bean只注冊了一次,所以一定滿足條件。

執行結果如下圖14:


六、@ConditionalOnResource注解

這個注解用於檢測類路徑中是否包含指定的資源。一般也就是文件了。

我們來檢測下配置文件,如下圖15:


肯定是存在的,執行結果如下圖16:




自定義條件注解



需要實現一個條件接口,如下圖17:


只有一個方法,返回true表示匹配上,false則相反。

方法的第一個參數,是一個上下文,如下圖18:


這里有很多的東西供我們使用。

方法的第二個參數,是最終標有我們定義好的條件注解的那個類,這個一定要明白。

我們來定義兩個和操作系統對應的注解,一個用於Windows,一個用於Linux。

Windows版本的實現,如下圖19:


從Environment中讀出操作系統的名稱,看是否包含windows即可。

Linux版本的實現,如下圖20:


原理和剛剛的一樣。

再定義兩個注解,分別和這兩個條件實現類關聯起來。

Windows版本的,如下圖21


Linux版本的,如下圖22:


然后開始試用一下這兩個條件注解,如下圖23:


因為我用的是Windows,所以肯定只有@Windows注解可以匹配。

執行結果如下圖24:


這只是一個簡單的示例,可以根據自己的需要定義更加復雜的,但是原理和流程都是一樣的。

>>> 玩轉SpringBoot系列文章 <<<

 

【玩轉SpringBoot】配置文件yml的正確打開姿勢

 

>>> 品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年,我有話說

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

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

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

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

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

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

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

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

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

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

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

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

品Spring:帝國的基石

 

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

  


免責聲明!

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



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