上篇博客我們詳細的聊了《JavaEE開發之Spring中的多線程編程以及任務定時器詳解》,本篇博客我們就來聊聊條件注解@Conditional以及組合條件。條件注解說簡單點就是根據特定的條件來選擇Bean對象的創建。條件注解就是可以根據不同的條件來做出不同的事情。在Spring中條件注解可以說是設計模式中狀態模式的一種體現方式,同時也是面向對象編程中多態的應用部分。而組合注解就是將現有的注解進行組合。下方會給出具體的介紹和實例。
一、條件注解----@Conditional
本篇博客的本部分我們來聊一下條件注解,顧名思義,條件注解就是可以根據不同的條件來做出不同的事情。在Spring中條件注解可以說是設計模式中狀態模式的一種體現方式,同時也是面向對象編程中多態的應用部分。
在Spring框架中,當我們使用條件注解時,我們會為每種獨立的條件創建一個類,根據這個類對應的條件的成立情況我們來選擇不同的任務來執行。當然我們在聲明任務時,一般使用接口來聲明。因為我們會在Spring的配置類中指定具體條件下的具體類。接下來,我們將來看一下Spring框架中@Conditional注解的具體使用方式。
當然同一個Service接口所對應的條件集合中是互斥的,也就是說在特定情況下只有一個條件成立。
1、創建服務接口以及具體的服務類
首先我們來創建一個Service的接口,然后再基於遵循該接口的情況下來創建兩個Service類。下方我們將會在配置類中指定不同條件下會對應不同的Service對象。首先我們先來創建Service的接口。下方這段代碼就是我們創建的Service的接口,該接口比較簡單,只有一個描述方法。在具體是Service類中我們將會給出description()方法的具體實現,用此方法來區分不同類的實現。
package com.zeluli.conditional; public interface ConditinalServiceInteface { public String description(); }
創建完ServiceInterface后,我們就該創建具體的類了。下方的FirstConditionService和SecondConditionService兩個類都實現了ConditinalServiceInteface接口,並且給出了description()方法的具體實現。稍后,我們將會在下方類配置Bean時,給出相應的條件。本小節只是准備部分。
package com.zeluli.conditional; public class FirstConditionService implements ConditinalServiceInteface { public String description() { return "第一個條件成立的Service"; } } ========================================= package com.zeluli.conditional; public class SecondConditionService implements ConditinalServiceInteface { public String description() { return "第二個條件成立的Service"; } }
2、創建@Conditional對應的條件類
創建完Service接口以及Service類后,接下來我們就來創建@Conditional注解所需的條件類。每個條件類對應着一種獨立的情況,在Spring中的條件類需要實現Condition接口。下方是我們創建的兩個條件類。
這兩個條件類都實現了Spring框架中的Condition,並且給出了matches()方法的實現。matches()方法的返回值是一個布爾類型的值,如果返回false說明該條件類所對應的條件不成立,如果返回true則說明該條件對應的條件成立。為了簡化操作,我們就指定FirstConditional對應的條件為false,而SecondConditional對應的條件為true。具體的條件類的實現如下所示。
package com.zeluli.conditional; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata; public class FirstConditional implements Condition { //提供條件的方法 public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { return false; } } ========================================== package com.zeluli.conditional; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata; public class SecondConditional implements Condition { public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { return true; } }
3.在Java配置類中進行條件配置
Service的接口、Service的類以及相應的條件創建完畢后,接下來我們就該在Java的配置類中將條件類與Service類對象進行關聯了。下方代碼段就是該部分對應的配置類。在聲明FirstConditionService類的Bean時,我們使用@Conditional注解,@Conditional的參數為FirstConditional.class,也就是說明當FirstConditional類所對應的條件成立時FirstConditionService的對象才會被實例化。
同理,下方的SecondConditionService對應的條件是SecondConditional。具體代碼如下所示。
package com.zeluli.conditional; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan("com.zeluli.conditional") public class ConditionalConfig { @Bean @Conditional(FirstConditional.class) //指定條件類 public FirstConditionService getFirstConditionalService() { return new FirstConditionService(); } @Bean @Conditional(SecondConditional.class) public SecondConditionService getSecondConditionService() { return new SecondConditionService(); } }
4、創建Main方法進行測試
接下來又到了測試的時刻了,下方我們從上面的ConditionalConfig配置類中獲取上下文,然后從上下文中獲取相應的Service對象。在獲取對象時,我們使用的是ConditionalServiceInterface接口來獲取和聲明的Bean。也就是說service變量所承載的對象是實現ConditionalServiceInterface接口的所有類中的某個類的對象。當某個Service類所對應的條件成立時,該類的對象就會被創建。
上面我們也提到過,ConditionalServiceInterface接口下每個類對應的這些條件必須是互斥的,也就是這些條件在特定情況下只有一個是成立的。因為我們為第二個條件返回的是true, 所以該條件是成立的,那么SecondConditionalService類的對象就會被調用。所以我們調用service的description()方法時,調用的是SecondConditionalService類中的相應的方法。具體如下所示。
二、組合注解
組合注解這個就比較好理解了,就是將多個注解組合到一塊生成一個新的注解。使用這個新的注解就相當於使用了該組合注解中所有的注解。這個特性還是蠻有用的,接下來我們就來看一下如何創建和使用組合注解。
1.組合注解的創建
接下來我們就通過一個簡單的實例來看一下如何將多個注解組合到一塊。在之前的Spring配置類中,我們經常使用到@Configuration和@ComponentScan這兩個注解,接下來,我們將其進行組合封裝,從而形成一個新的注解。
下方這個CombinationConfiguration注解就是我們組合的新的注解,該注解中使用了@Configuration和@ComponentScan進行修飾,也就說明@CombinationConfiguration注解兼有@Configuration和@ComponentScan這兩個注解的功能。
package com.zeluli.combination.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration @ComponentScan public @interface CombinationConfiguration { String[] value() default{}; }
2.組合注解的使用
創建完相應的組合注解后就到了使用的時候了,上面注解的使用和一般的注解沒有什么區別。只是這個注解表示之前寫的@Configuration和@ComponentScan這兩個注解。下方代碼截圖就是該組合注解的使用方式。
OK,今天博客就先到這兒吧,github源碼分享地址:https://github.com/lizelu/SpringDemo