javascript
一篇文章教你读懂Spring @Conditional注解
文章目錄
- 一、Conditional簡介
- 二、Conditional用法
- 1、Conditonal注解作用在方法上
- 2、Conditonal注解作用在類上
- 3、類上注入多個條件類
- 三、Conditional擴(kuò)展
寫在前面:
我是「境里婆娑」。我還是從前那個少年,沒有一絲絲改變,時間只不過是考驗(yàn),種在心中信念絲毫未減,眼前這個少年,還是最初那張臉,面前再多艱險不退卻。
寫博客的目的就是分享給大家一起學(xué)習(xí)交流,如果您對 Java感興趣,可以關(guān)注我,我們一起學(xué)習(xí)。
前言:Conditional在項(xiàng)目中經(jīng)常用到,其作用是按照一定的條件進(jìn)行判斷,滿足條件給容器注冊bean。如果感興趣的同學(xué)可以跟著我一起去一步步去揭開這個注解的面紗。
一、Conditional簡介
@Conditional是Spring4新提供的注解,它的作用是按照一定的條件進(jìn)行判斷,滿足條件給容器注冊bean。
@Conditional定義:
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Conditional {/*** All {@link Condition Conditions} that must {@linkplain Condition#matches match}* in order for the component to be registered.*/Class<? extends Condition>[] value();}@FunctionalInterface public interface Condition {boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);}從代碼中可以看出:
1、這個注解可以作用到類和方法上
2、傳入一個Class數(shù)組,并且需要繼承Condition接口,需要實(shí)現(xiàn)matches方法,返回true則注入bean,false則不注入。
二、Conditional用法
1、創(chuàng)建一個car類
/*** @author shuliangzhao* @Title: Car* @ProjectName spring-boot-learn* @Description: TODO* @date 2020/11/21 11:08*/ public class Car {private String color;private String brand;public Car(String color, String brand) {this.color = color;this.brand = brand;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}public String getBrand() {return brand;}public void setBrand(String brand) {this.brand = brand;}@Overridepublic String toString() {return "Car{" +"color='" + color + '\'' +", brand='" + brand + '\'' +'}';} }2、創(chuàng)建ConditionalConfig類,用于配置兩個Card實(shí)例并注入
/*** @author shuliangzhao* @Title: ConditionConfig* @ProjectName spring-boot-learn* @Description: TODO* @date 2020/11/21 11:10*/ @Configuration public class ConditionConfig {@Beanpublic Car car1() {return new Car("red","奧迪");}@Beanpublic Car car2() {return new Car("blue","寶馬");} }3、創(chuàng)建一個SpringUtil獲取容器bean工具類
@Component public class SpringUtil implements ApplicationContextAware {private static ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {if(SpringUtil.applicationContext == null) {SpringUtil.applicationContext = applicationContext;}}//獲取applicationContextpublic static ApplicationContext getApplicationContext() {return applicationContext;}//通過name獲取 Bean.public static Object getBean(String name){return getApplicationContext().getBean(name);}//通過class獲取Bean.public static <T> T getBean(Class<T> clazz){return getApplicationContext().getBean(clazz);}//通過name,以及Clazz返回指定的Beanpublic static <T> T getBean(String name,Class<T> clazz){return getApplicationContext().getBean(name, clazz);} }4、啟動程序查看結(jié)果
@SpringBootApplication public class SpringBootExmpleApplication {public static void main(String[] args) {SpringApplication.run(SpringBootExmpleApplication.class, args);System.out.println(SpringUtil.getBeansOfType(Car.class));} }運(yùn)行,輸出結(jié)果,兩個car實(shí)例被注入進(jìn)容器。
Car{color=‘red’, brand=‘奧迪’} Car{color=‘blue’, brand=‘寶馬’}
如果我想根據(jù)當(dāng)前操作系統(tǒng)來注入Car實(shí)例,windows下注入奧迪,linux下注入寶馬,怎么做?
這就需要我們用到@Conditional注解了,前言中提到,需要實(shí)現(xiàn)Condition接口,并重寫方法來自定義match規(guī)則。
創(chuàng)建WindowsCondition類
public class WindowsCondition implements Condition {@Overridepublic boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {//獲取ioc使用的beanFactoryConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();//獲取類加載器ClassLoader classLoader = conditionContext.getClassLoader();//獲取當(dāng)前環(huán)境信息Environment environment = conditionContext.getEnvironment();//獲取bean定義的注冊類BeanDefinitionRegistry registry = conditionContext.getRegistry();//獲得當(dāng)前系統(tǒng)名String property = environment.getProperty("os.name");//包含Windows則說明是windows系統(tǒng),返回trueif (property.contains("Windows")){return true;}return false;} }創(chuàng)建LinuxCondition類
public class LinuxCondition implements Condition {@Overridepublic boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {Environment environment = conditionContext.getEnvironment();String property = environment.getProperty("os.name");if (property.contains("Linux")){return true;}return false;} }注意:matches方法的conditionContext提供了多種方法,方便獲取各種信息。
1、Conditonal注解作用在方法上
@Configuration public class ConditionConfig {@Bean@Conditional({WindowsCondition.class})public Car car1() {return new Car("red","奧迪");}@Bean@Conditional({LinuxCondition.class})public Car car2() {return new Car("blue","寶馬");} }運(yùn)行結(jié)果如下:
當(dāng)前系統(tǒng)為:Windows 8.1
Car{color=‘red’, brand=‘奧迪’}
修改運(yùn)行時參數(shù),運(yùn)行l(wèi)inux
運(yùn)行結(jié)果如下:
當(dāng)前系統(tǒng)為:Linux
Car{color=‘blue’, brand=‘寶馬’}
總結(jié): 一個方法只能注入一個bean實(shí)例,所以@Conditional標(biāo)注在方法上只能控制一個bean實(shí)例是否注入。
2、Conditonal注解作用在類上
@Conditional標(biāo)注在類上就決定了一批bean是否注入。
ConditionConfig改寫,如果WindowsCondition返回true,則兩個Car實(shí)例將被注入(注意:上一個測試將os.name改為linux,這是我將把這個參數(shù)去掉):
@Configuration @Conditional({WindowsCondition.class}) public class ConditionConfig {@Beanpublic Car car1() {return new Car("red","奧迪");}@Beanpublic Car car2() {return new Car("blue","寶馬");} }運(yùn)行結(jié)果如下:
當(dāng)前系統(tǒng)為:Windows 8.1 {car1=Car{color=‘red’, brand=‘奧迪’},
car2=Car{color=‘blue’, brand=‘寶馬’}}
如果將類上的WindowsCondition.class改為LinuxCondition.class,運(yùn)行結(jié)果為:{}
3、類上注入多個條件類
@Conditional注解傳入的是一個Class數(shù)組,存在多種條件類的情況,新增新的條件類,實(shí)現(xiàn)的matches返回false
public class TestCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {return false;} }運(yùn)行結(jié)果為:
當(dāng)前系統(tǒng)為:Windows 8.1
{}
現(xiàn)在將TestCondition 返回結(jié)果改為true
運(yùn)行結(jié)果為:
當(dāng)前系統(tǒng)為:Windows 8.1 {car1=Car{color=‘red’, brand=‘奧迪’},
car2=Car{color=‘blue’, brand=‘寶馬’}}
總結(jié)如下:
第一個條件類實(shí)現(xiàn)的方法返回true,第二個返回false,則結(jié)果false,不注入進(jìn)容器。
第一個條件類實(shí)現(xiàn)的方法返回true,第二個返回true,則結(jié)果true,注入進(jìn)容器中。
三、Conditional擴(kuò)展
@ConditionalOnBean // 當(dāng)給定的在bean存在時,則實(shí)例化當(dāng)前Bean
@ConditionalOnMissingBean // 當(dāng)給定的在bean不存在時,則實(shí)例化當(dāng)前Bean
@ConditionalOnClass // 當(dāng)給定的類名在類路徑上存在,則實(shí)例化當(dāng)前Bean
@ConditionalOnMissingClass // 當(dāng)給定的類名在類路徑上不存在,則實(shí)例化當(dāng)前Bean
如果想詳細(xì)了解請移步看這篇文章SpringBoot(16)—@ConditionalOnBean與@ConditionalOnClass
到此Spring中的Conditional介紹完畢。如果還有不明白的可以留言。
—————————————————————————————————
由于本人水平有限,難免有不足,懇請各位大佬不吝賜教!
總結(jié)
以上是生活随笔為你收集整理的一篇文章教你读懂Spring @Conditional注解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring IOC注入Map接口小技巧
- 下一篇: 致命问题多数据源引发SpringBatc