上篇博客我們詳細(xì)的聊了《JavaEE開發(fā)之Spring中的多線程編程以及任務(wù)定時(shí)器詳解》,本篇博客我們就來聊聊條件注解@Conditional以及組合條件。條件注解說簡單點(diǎn)就是根據(jù)特定的條件來選擇Bean對象的創(chuàng)建。條件注解就是可以根據(jù)不同的條件來做出不同的事情。在Spring中條件注解可以說是設(shè)計(jì)模式中狀態(tài)模式的一種體現(xiàn)方式,同時(shí)也是面向?qū)ο缶幊讨卸鄳B(tài)的應(yīng)用部分。而組合注解就是將現(xiàn)有的注解進(jìn)行組合。下方會(huì)給出具體的介紹和實(shí)例。
一、條件注解----@Conditional
本篇博客的本部分我們來聊一下條件注解,顧名思義,條件注解就是可以根據(jù)不同的條件來做出不同的事情。在Spring中條件注解可以說是設(shè)計(jì)模式中狀態(tài)模式的一種體現(xiàn)方式,同時(shí)也是面向?qū)ο缶幊讨卸鄳B(tài)的應(yīng)用部分。
在Spring框架中,當(dāng)我們使用條件注解時(shí),我們會(huì)為每種獨(dú)立的條件創(chuàng)建一個(gè)類,根據(jù)這個(gè)類對應(yīng)的條件的成立情況我們來選擇不同的任務(wù)來執(zhí)行。當(dāng)然我們在聲明任務(wù)時(shí),一般使用接口來聲明。因?yàn)槲覀儠?huì)在Spring的配置類中指定具體條件下的具體類。接下來,我們將來看一下Spring框架中@Conditional注解的具體使用方式。
當(dāng)然同一個(gè)Service接口所對應(yīng)的條件集合中是互斥的,也就是說在特定情況下只有一個(gè)條件成立。
1、創(chuàng)建服務(wù)接口以及具體的服務(wù)類
首先我們來創(chuàng)建一個(gè)Service的接口,然后再基于遵循該接口的情況下來創(chuàng)建兩個(gè)Service類。下方我們將會(huì)在配置類中指定不同條件下會(huì)對應(yīng)不同的Service對象。首先我們先來創(chuàng)建Service的接口。下方這段代碼就是我們創(chuàng)建的Service的接口,該接口比較簡單,只有一個(gè)描述方法。在具體是Service類中我們將會(huì)給出description()方法的具體實(shí)現(xiàn),用此方法來區(qū)分不同類的實(shí)現(xiàn)。
package com.zeluli.conditional;public interface ConditinalServiceInteface { public String description(); }
創(chuàng)建完ServiceInterface后,我們就該創(chuàng)建具體的類了。下方的FirstConditionService和SecondConditionService兩個(gè)類都實(shí)現(xiàn)了ConditinalServiceInteface接口,并且給出了description()方法的具體實(shí)現(xiàn)。稍后,我們將會(huì)在下方類配置Bean時(shí),給出相應(yīng)的條件。本小節(jié)只是準(zhǔn)備部分。
package com.zeluli.conditional;public class FirstConditionService implements ConditinalServiceInteface { public String description() { return "第一個(gè)條件成立的Service"; } }=========================================package com.zeluli.conditional;public class SecondConditionService implements ConditinalServiceInteface { public String description() { return "第二個(gè)條件成立的Service"; } }
2、創(chuàng)建@Conditional對應(yīng)的條件類
創(chuàng)建完Service接口以及Service類后,接下來我們就來創(chuàng)建@Conditional注解所需的條件類。每個(gè)條件類對應(yīng)著一種獨(dú)立的情況,在Spring中的條件類需要實(shí)現(xiàn)Condition接口。下方是我們創(chuàng)建的兩個(gè)條件類。
這兩個(gè)條件類都實(shí)現(xiàn)了Spring框架中的Condition,并且給出了matches()方法的實(shí)現(xiàn)。matches()方法的返回值是一個(gè)布爾類型的值,如果返回false說明該條件類所對應(yīng)的條件不成立,如果返回true則說明該條件對應(yīng)的條件成立。為了簡化操作,我們就指定FirstConditional對應(yīng)的條件為false,而SecondConditional對應(yīng)的條件為true。具體的條件類的實(shí)現(xiàn)如下所示。
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配置類中進(jìn)行條件配置
Service的接口、Service的類以及相應(yīng)的條件創(chuàng)建完畢后,接下來我們就該在Java的配置類中將條件類與Service類對象進(jìn)行關(guān)聯(lián)了。下方代碼段就是該部分對應(yīng)的配置類。在聲明FirstConditionService類的Bean時(shí),我們使用@Conditional注解,@Conditional的參數(shù)為FirstConditional.class,也就是說明當(dāng)FirstConditional類所對應(yīng)的條件成立時(shí)FirstConditionService的對象才會(huì)被實(shí)例化。
同理,下方的SecondConditionService對應(yīng)的條件是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、創(chuàng)建Main方法進(jìn)行測試
接下來又到了測試的時(shí)刻了,下方我們從上面的ConditionalConfig配置類中獲取上下文,然后從上下文中獲取相應(yīng)的Service對象。在獲取對象時(shí),我們使用的是ConditionalServiceInterface接口來獲取和聲明的Bean。也就是說service變量所承載的對象是實(shí)現(xiàn)ConditionalServiceInterface接口的所有類中的某個(gè)類的對象。當(dāng)某個(gè)Service類所對應(yīng)的條件成立時(shí),該類的對象就會(huì)被創(chuàng)建。
上面我們也提到過,ConditionalServiceInterface接口下每個(gè)類對應(yīng)的這些條件必須是互斥的,也就是這些條件在特定情況下只有一個(gè)是成立的。因?yàn)槲覀優(yōu)榈诙€(gè)條件返回的是true, 所以該條件是成立的,那么SecondConditionalService類的對象就會(huì)被調(diào)用。所以我們調(diào)用service的description()方法時(shí),調(diào)用的是SecondConditionalService類中的相應(yīng)的方法。具體如下所示。
二、組合注解
組合注解這個(gè)就比較好理解了,就是將多個(gè)注解組合到一塊生成一個(gè)新的注解。使用這個(gè)新的注解就相當(dāng)于使用了該組合注解中所有的注解。這個(gè)特性還是蠻有用的,接下來我們就來看一下如何創(chuàng)建和使用組合注解。
1.組合注解的創(chuàng)建
接下來我們就通過一個(gè)簡單的實(shí)例來看一下如何將多個(gè)注解組合到一塊。在之前的Spring配置類中,我們經(jīng)常使用到@Configuration和@ComponentScan這兩個(gè)注解,接下來,我們將其進(jìn)行組合封裝,從而形成一個(gè)新的注解。
下方這個(gè)CombinationConfiguration注解就是我們組合的新的注解,該注解中使用了@Configuration和@ComponentScan進(jìn)行修飾,也就說明@CombinationConfiguration注解兼有@Configuration和@ComponentScan這兩個(gè)注解的功能。
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 @ComponentScanpublic @interface CombinationConfiguration { String[] value() default{}; }
2.組合注解的使用
創(chuàng)建完相應(yīng)的組合注解后就到了使用的時(shí)候了,上面注解的使用和一般的注解沒有什么區(qū)別。只是這個(gè)注解表示之前寫的@Configuration和@ComponentScan這兩個(gè)注解。下方代碼截圖就是該組合注解的使用方式。