1. @Conditional
首先来看一下@Conditional注解的源码:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
Class<? extends Condition>[] value();
}
可以看出这个注解接收的是一个Condition的类的数组,由Condition的源码知道,它有一个返回boolean的方法matches,由此可猜测,这个注解会根据Condition的matches方法的返回值来确定注入的bean。下面来看一个例子:
public class DevCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return "dev".equalsIgnoreCase(conditionContext.getEnvironment().getActiveProfiles()[0]);
}
}
public class TestCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return "test".equalsIgnoreCase(conditionContext.getEnvironment().getActiveProfiles()[0]);
}
}
@Configuration
public class ConditionTestConfig {
@Bean
@Conditional(DevCondition.class)
public Environment devEnvironment(){
Environment dev = new Environment();
dev.setName("dev");
return dev;
}
@Bean
@Conditional(DevCondition.class)
public Environment testEnvironment(){
Environment test = new Environment();
test.setName("test");
return test;
}
}
测试类代码:
@RunWith(value = SpringJUnit4ClassRunner.class)
@SpringBootTest(classes={StartClass.class})
public class ConditionTest {
@Autowired
private Environment environment;
@Test
public void testGetEnvironmentConfig(){
System.out.println(environment.getName());
}
}
结果如下:
1. 当我们设置spring.profiles.active为dev的时候,打印结果是dev,所以初始化的是devEnvironment
2. 当我们设置spring.profiles.active为test的时候,打印结果是test,所以初始化的是testEnvironment
3. 再次测试如果传入Condition数组的时候,必须所有的Condition都返回true才会命中
4. 注入的同一个类型的bean不能同时命中多个(即不能有冲突)
5. 不能出现所有的条件都不满足的情况(至少有一个@Conditional是命中的的)
2. @ConditionalOnBean和@ConditionalOnMissingBean
首先来看一下@ConditionalOnBean的源码:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({OnBeanCondition.class})
public @interface ConditionalOnBean {
Class<?>[] value() default {};
String[] type() default {};
Class<? extends Annotation>[] annotation() default {};
String[] name() default {};
SearchStrategy search() default SearchStrategy.ALL;
Class<?>[] parameterizedContainer() default {};
}
由注解源码可以看出,它其实就是对@Conditional的增强,应该是帮我们实现了Condition的方法。根据这个注解的名称,我们可以猜测出只要我们指定的bean在这个容器中,那么就算命中了,例如:
@ConditionalOnBean(Person.class)
只要我们指定的类对应的bean在容器中,那么就算命中,这里除了可以指定bean的类型,也可以通过type指定类的路径,也可以通过通过name指定bean的名称
而@ConditionalOnMissingBean和@ConditionalOnBean和是正好相反的,如果参数中的bean不在容器中,那么就算命中了。
3. 其他的spring实现的注解
spring除了帮我们实现ConditionalOnMissingBean和@ConditionalOnBean,还帮我们实现以下的注解:
@ConditionalOnClass
如果指定的Class是存在的,那么就命中:@ConditionalOnClass(Person.class)或者@ConditionalOnClass(name = {"com.springboot.Person"})
@ConditionalOnMissingClass
和ConditionalOnClass相反,如果指定的class不存在,那么命中:@ConditionalOnMissingClass(value = {"com.springboot.Person"})
@ConditionalOnExpression
如果指定的表达式的值为true,那么命中:@ConditionalOnExpression("true")或@ConditionalOnExpression("${}")
@ConditionalOnNotWebApplication
当该应用为web应用的时候,命中