从零学springboot—— Conditional系列注解

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应用的时候,命中
发布了81 篇原创文章 · 获赞 16 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/mazhen1991/article/details/99694180