上一篇文章 你應該知道的 @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-pro...
總結
到這裡,你已經瞭解瞭如何靈活配置 bean,結合之前的文章,相信的定義會更加靈活,希望大家開啟 IDE,自行檢視這些註解,瞭解更多具體內容
靈魂追問
- SpringBoot 新增了 web starter,有哪些方法將其更改為非 web 應用?
- Java8 Stream 也有 findAny,findAll 這類的操作,這都是匹配,你有使用過嗎?
- 看下面這段程式碼,如果 classpath 中沒有 MyBean class,編譯會報錯,那這個註解什麼用呢?
@Configuration
@ConditionalOnClass(MyBean.class)
public class MyConfiguration{
// omitted
}
提高效率工具
推薦閱讀
- 每天用SpringBoot,還不懂RESTful API返回統一資料格式是怎麼實現的?
- 雙親委派模型:大廠高頻面試題,輕鬆搞定
- 面試還不知道BeanFactory和ApplicationContext的區別?
- 如何設計好的RESTful API
- 紅黑樹,超強動靜圖詳解,簡單易懂
歡迎持續關注公眾號:「日拱一兵」
- 前沿 Java 技術乾貨分享
- 高效工具彙總 | 回覆「工具」
- 面試問題分析與解答
- 技術資料領取 | 回覆「資料」
以讀偵探小說思維輕鬆趣味學習 Java 技術棧相關知識,本著將複雜問題簡單化,抽象問題具體化和圖形化原則逐步分解技術問題,技術持續更新,請持續關注......