Spring Boot @Condition 注解,組合條件你知道嗎


上一篇文章 你應該知道的 @ConfigurationProperties 注解的使用姿勢,這一篇就夠了 介紹了如何通過 @ConfigurationProperties 注解靈活讀取配置屬性,這篇文章將介紹如何靈活配置 Spring Bean

寫在前面

當我們構建一個 Spring 應用的時候,有時我們想在滿足指定條件的時候才將某個 bean 加載到應用上下文中, 在Spring 4.0 時代,我們可以通過 @Conditional 注解來實現這類操作

我們看到 @Conditional 注解接收的參數是 extends Condition 接口的泛型類,也就是說,我們要使用 @Conditional 注解,只需要實現 Condition 接口並重寫其方法即可:

看到接口的 matches 方法返回的是 boolean 類型,是不是和我們自定義 validation annotation 有些類似,都是用來判斷是否滿足指定條件。另外注意看,以上注解和接口都在 org.springframework.context.annotation package 中

終於到了 Spring Boot 時代,在這個全新的時代,Spring Boot 在 @Conditional 注解的基礎上進行了細化,無需出示復雜的介紹信 (實現 Condition 接口),只需要手持預定義好的 @ConditionalOnXxxx 注解印章的門票,如果驗證通過,就會走進 Application Context 大廳

注解詳解

Spring Boot 對 @Conditional 注解為我們做了細化,這些注解都定義在 org.springframework.boot.autoconfigure.condition package 下

逐個打開這 13 個注解,我們發現這些注解上有相同的元注解:

從這些標記上我們可以了解如下內容:

  • 都可以應用在 TYPE 上,也就是說,Spring 自動掃描的一切類 (@Configuration, @Component, @Service, @Repository, or @Controller) 都可以通過添加相應的 @ConditionalOnXxxx 來判斷是否加載

  • 都可以應用在 METHOD 上,所以有 @Bean 標記的方法也可以應用這些注解

  • 都是用了 @Conditional 注解來標記,OnBeanCondition 等自定義 Condition 還是實現了 Condition 接口的,換湯不換葯,沒什么神秘的,只不過做了更具象的封裝罷了,來看類依賴圖:

其實看這些注解字面意思已經能理解這些注解的含義,但是我們還是要說明具體的使用以及一些注意事項,我按照個人使用頻次由高到低講解:

@ConditionalOnProperty

毫無疑問這個注解是榜首

這個條件解釋是: application.properties 或 application.yml 文件中 mybean.enable 為 true 才會加載 MyCondition 這個 Bean,如果沒有匹配上也會加載,因為 matchIfMissing = true,默認值是 false。

@ConditionalOnBean 和 ConditionalOnMissingBean

有時候我們需要某個 Bean 已經存在應用上下文時才會加載,那么我們會用到 @ConditionalOnBean 注解:

與之相反,有時候我們需要某個 Bean 不存在於應用上下文時才會加載,那么我們會用到 @ConditionalOnMissingBean 注解

@ConditionalOnClass 和 @ConditionalOnMissingClass

不要嫌我廢話,和上面的一樣,只不過判斷某個類是否存在於 classpath 中,這就不做過多說明了

@ConditionalOnExpression

如果我們有更復雜的多個配置屬性一起判斷,那么我們就可以用這個表達式了:

只有當兩個屬性都為 true 的時候才加載 MyModule,到這里要順便揭曉上一篇文章 你應該知道的 @ConfigurationProperties 注解的使用姿勢,這一篇就夠了 靈魂追問 3,其中 :true 就是: 如果沒有為該屬性設置值,則為該屬性設置默認值true, 其實這就是@Vaue 注解的規范,一切 SpEL 都可以應用在這里.

寫到這,我常用的已經用完了,還要硬着頭皮介紹其他幾個內容 😄,開個玩笑,咱們繼續:

@ConditionalOnSingleCandidate

這個注解和 @ConditionalOnBean 類似,為了更好的說明該注解的使用 (其實是 才疏學淺 ) ,我只能翻譯一下類的注釋了

只有指定類已存在於 BeanFactory 中,並且可以確定單個候選項才會匹配成功

BeanFactory 存在多個 bean 實例,但是有一個 primary 候選項被指定(通常在類上使用 @Primary 注解),也會匹配成功。實質上,如果自動連接具有定義類型的 bean 匹配就會成功

目前,條件只是匹配已經被應用上下文處理的 bean 定義,本身來講,強烈建議僅僅在 auto-configuration 類中使用這個條件,如果候選 bean 被另外一個 auto-configuration 創建,確保使用該條件的要在其后面運行

@ConditionalOnResource

如果我們要加載的 bean 依賴指定資源是否存在於 classpath 中,那么我們就可以使用這個注解

看到這個 logback.xml 是不是很親切,在我們引入第三方工具類如 Dozer 等都可以添加類似的開關

接下來的是真冷門,大家有個印象,如果有需要,至少能想到用這些注解實現靈活配置就好了

@ConditionalOnJndi

只有指定的資源通過 JNDI 加載后才加載 bean

@ConditionalOnJava

只有運行指定版本的 Java 才會加載 Bean

@ConditionalOnWebApplication 和 @ConditionalOnNotWebApplication

只有運行在 web 應用里才會加載這個 bean

與之相反,在非 web 環境才加載 bean

@ConditionalOnCloudPlatform

這個注解冷的我呼吸都要停止了,只有運行在指定的雲平台上才加載指定的 bean,CloudPlatform 是 org.springframework.boot.cloud 下一個 enum 類型的類,大家可以打開自行看看:

到此,Spring Boot 為我們提供的這 13 個注解就介紹完了,但是沒有結束,下面的一些冷門知識,你需要知道:

組合條件

組合條件 AND

如果我們想多個條件一起應用,並且條件的關系是 and,我們只需要在類上使用多個@ConditionalOnXxxx 就可以了 (你這也叫冷門?) ,當然也可以繼承 AllNestedConditions類封裝我們多個條件

這樣就有了組合 and 條件,只有內部所有條件都滿足,才加載指定 bean

組合條件 OR

如果我們希望組合的條件是 or 的關系,我們該怎么辦呢? 我們可以通過繼承 AnyNestedCondition 來完成這一要求,示例代碼和上面一樣,大家自行打開 AnyNestedCondition 類,查看類說明即可

條件組合 NONE

有 and 和 or 就肯定有 non(非),我們可以通過繼承 NoneNestedConditions 完成這一要求,大家自行查看即可

自定義注解

通過組合方式實現了多條件邏輯應用,我們需要應用這些組合條件也就要自定義注解,其實文章開頭已經講過了,模仿內置的 13 個注解寫就好了:

只需要通過@Conditional注解指定我們自定義的 condition 類就好了,然后應用到你想用的地方就好了

還是推薦大家看 RabbitMq 的 RabbitAutoConfiguration 類,這個類里面主流的注解都是用了 (只看這一個類就好了),大家看框架理解學習這些注解是更好的方式:

https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java

總結

到這里,你已經了解了如何靈活配置 bean,結合之前的文章,相信的定義會更加靈活,希望大家打開 IDE,自行查看這些注解,了解更多具體內容

靈魂追問

  1. SpringBoot 添加了 web starter,有哪些方法將其更改為非 web 應用?
  2. Java8 Stream 也有 findAny,findAll 這類的操作,這都是匹配,你有使用過嗎?
  3. 看下面這段代碼,如果 classpath 中沒有 MyBean class,編譯會報錯,那這個注解什么用呢?
@Configuration    
@ConditionalOnClass(MyBean.class)
public class MyConfiguration{
    // omitted       
}
```## 提高效率工具

![](http://rgyb.sunluomeng.top/%E5%85%AC%E4%BC%97%E8%B4%A6%E5%8F%B7%E6%96%87%E7%AB%A0/%E6%84%9F%E6%83%B3%E4%B8%8E%E6%80%BB%E7%BB%93/_image/2019-06-18/b.png) 

--------

## 推薦閱讀
+ [紅黑樹,超強動靜圖詳解,簡單易懂](https://mp.weixin.qq.com/s/ilND8u_8HGSTSrJiMB4X8g)
+ [雙親委派模型:大廠高頻面試題,輕松搞定](https://mp.weixin.qq.com/s/Dnr1jLebvBUHnziZzSfcrA)
+ [面試還不知道BeanFactory和ApplicationContext的區別?](https://mp.weixin.qq.com/s/YBQB086ADBjHUmwrFQrWew)
+ [如何設計好的RESTful API](https://mp.weixin.qq.com/s/hR1TqkVzwZ_T8fuMnsM4hQ)
+ [程序猿為什么要看源碼?](https://mp.weixin.qq.com/s/V7h8O6pVFQ-nr_iA2SNqtw)

--------
> ### 歡迎持續關注公眾號:「日拱一兵」
> - 前沿 Java 技術干貨分享 
> - 高效工具匯總 
> - 面試問題分析與解答 
> - 技術資料領取
**后續會推出 「多線程」以及「ElasticSearch」等連載內容**
> 以讀偵探小說思維輕松趣味學習 Java 技術棧相關知識,本着將復雜問題簡單化,抽象問題具體化和圖形化原則逐步分解技術問題,技術持續更新,請持續關注......

![](http://rgyb.sunluomeng.top/%E5%85%AC%E4%BC%97%E8%B4%A6%E5%8F%B7%E6%96%87%E7%AB%A0/%E6%84%9F%E6%83%B3%E4%B8%8E%E6%80%BB%E7%BB%93/_image/2019-06-18/a%20%281%29.png)


免責聲明!

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



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