@Conditional注解用于注册Bean时的条件判断,满足注解的条件则把定义的bean注入到容器中
@Conditional的使用
我们先看下@Conditional的源码
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
/**
* All {@link Condition}s that must {@linkplain Condition#matches match}
* in order for the component to be registered.
*/
Class<? extends Condition>[] value();
}
从源码我们可以直观的获取到以下信息
@Target注解的值是ElementType.TYPE和ElementType.METHOND,说明该注解可以作用在类和方法上面value需要传入一个class数组,类型是Condition或者Condition的子类,其中Condition是一个接口
下面展示下作用在方法上面的注解,首先是实现Condition的两个子类(根据业务可以有多个实现),接口只有一个方法。方法返回值类型是boolean,当返回值为true时表示满足条件,可以注入到容器中。这里我们让ChinaCondition实现类的方法返回true,EnglishCondition实现类返回false
public class ChinaCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return true;
}
}
public class EnglishCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return false;
}
}
业务实现类
public interface Speak {
}
public class EnglishSpeak implements Speak {
public EnglishSpeak() {
System.out.println("speak english");
}
}
public class ChineseSpeak implements Speak {
public ChineseSpeak() {
System.out.println("speak chinese");
}
}
配置类
@Configuration
public class DemoConfig {
@Conditional({ChinaCondition.class})
@Bean
public Speak chineseSpeak() {
return new ChineseSpeak();
}
@Conditional({EnglishCondition.class})
@Bean
public Speak englishSpeak() {
return new EnglishSpeak();
}
}
测试类
public class ApplicationTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(DemoConfig.class);
Map<String, Speak> beansOfType = applicationContext.getBeansOfType(Speak.class);
System.out.println(beansOfType);
}
}
执行结果:
从上面执行结果可以看出,EnglishSpeak并没有注入到容器中,因为EnglishCondition实现类中的方法返回的false,不满足条件,所以没有注入到容器中。
注解作用在类上和作用在方法上的使用方式类似,只是作用范围不一样,当满足条件时,配置类中配置的所有的Bean都会注入到容器中。这种方式相比于作用于方法上面的方式粒度比较粗,但是效果都是一样的。
注意:我们看到value是个数组,如果配置了多个
conditional则需要所有的都返回true才能将bean注入到容器中,也就是说所有条件之间是且的关系而不是或的关系
@Conditional扩展
@Conditional是最基本的使用方式,需要我们自定义很多实现方式,Spring boot也为我们提供了很多常用的实现,能够让我们开箱即用
@ConditionalOnBean:当容器上下文中有指定的bean实例时才会进行实例化@ConditionalOnMissingBean:当容器上下文中没有指定的bean实例时才会进行实例化@ConditionalOnClass:当类路径下有指定的类时才会进行实例化@ConditionalOnMissingClass:当类路径下没有指定的类时才会进行实例化@ConditionalOnJava:当jvm版本为指定的版本范围时才会进行实例化@ConditionalOnResource:当类路径下有指定的资源时才会进行实例化
示例:
-
@ConditionalOnJava(value = JavaVersion.EIGHT,range = ConditionalOnJava.Range.EQUAL_OR_NEWER):当jdk的版本大于等于1.8时,才会实例化该类 -
@ConditionalOnResource(resources = {"dev.properties"}):当类路径下有文件dev.properties时才会实例化该类