@Conditional以及它的家族@ConditionalOnXXX -- 条件选择注入Bean


前言

  有一篇文章:《Spring Boot @Condition 注解,组合条件你知道吗》十分值得阅读


一、@Conditional的作用

1. @Conditional

    @Conditional注解可以作用在创建Bean的类或者方法上,给Spring容器是否加载此bean,添加额外的约束或者判断。

作用在:

  • 类注解(@Component、@Controller、@Service、@Repository)
  • 方法注解(@Bean)

的bean都可以用@Conditional做额外约束

    当@Conditional注解的判断条件不满足时,对应的Bean不会生成。

1. Condition接口

    根据上面的介绍,我们知道@Conditional注解是来让Spring容器选择是否加载对应bean的。也就是Spring可以通过**“某种判断”,来确定结果是true或false,进而决定是否加载此bean。
    在具体的实现上,
“这个判断”**是通过程序员实现Condition接口并重写public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata)方法来实现的。

二、使用示例

1. 编写Condition接口的实现

    编写一个我们自己的Condition接口的实现类:ConditionMatchService。这个实现类需要复写返回结果为布尔值的boolean match()方法。在match()方法中,我们编写判断条件:当环境为"condition"字符串时,返回为true;其他为false

/**
 * @Author: Albert Guo
 */
public class ConditionMatchService implements Condition {

    public static final String PROFILE = "condition";


    /**
     * 当此方法返回true时,注解生效
     * @param context
     * @param metadata
     * @return
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        String[] activeProfiles = environment.getActiveProfiles();
        if(ArrayUtils.isNotEmpty(activeProfiles)){
            for (int i = 0; i < activeProfiles.length; i++) {
                //当环境为condition时,返回true
                if (PROFILE.equals(activeProfiles[i])) {
                    return true;
                }
            }
        }
        return false;
    }
}

2.添加@Conditional注解

  在创建bean的地方添加@Conditional注解条件,并将刚编写的ConditionMatchService类作为判断条件添加

/**
 * @Author: Albert Guo
 */
@Configuration
public class ConditionConfiguration {

    /**
     * 如果ConditionMatchService的match()方法返回true,则ConditionDTO加载,会打印beanName
     * @return
     */
    @Bean(initMethod="init")
    @Conditional(ConditionMatchService.class)
    public ConditionDTO conditionDTO() {
        return new ConditionDTO();
    }
}

其中ConditionDTO内容如下,加入了必要的日志:

/**
 * @Author: Albert Guo
 */
@Slf4j
@Data
public class ConditionDTO implements BeanNameAware {

    //bean的名称
    private String beanName;

    public void init() {
        log.info("ConditionDTO 开始加载,beanName=={}", beanName);
    }

    @Override
    public void setBeanName(String name) {
        beanName = name;
    }
}

3. 编写Test测试类

/**
 * 测试{@code @Conditional}注解
 * @Author: Albert Guo
 */
@Slf4j
@ActiveProfiles("dev")
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {ConditionConfiguration.class})
public class ConditionTest implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Test
    public void test() {
        if(applicationContext.containsBean("conditionDTO")) {
            log.info("{}的bean存在!", ConditionMatchService.PROFILE);
        } else {
            log.warn("{}的bean不存在!", ConditionMatchService.PROFILE);
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

4. 测试结果

  1. 当Profile=dev时,可以看到bean并没有加载在这里插入图片描述
  2. 当Profile=condition时,可以看到bean加载成功
    在这里插入图片描述

三. @ConditionalOnXXX

  从上面的例子可以看到,@Condition一般要和Condition接口配合使用,还需要重写match()方法,开发起来并不是很精简。有时候编写框架时,设计师更在乎是否存在某个Bean、是否某个包或资源被引入、是否处于某种特殊环境下…对于这种存在与否的判断,可以抽象出某种共性,而不用再底层的每次重写match方法来逐个判断。
  因此SpringBoot基于@Condition接口,进一步封装了@ConditionalOnXXX注解。对于这些注解,开发者可以不用再实现Condition接口,而是直接在@ConditionalOnXXX注解的value值中,写入判断的条件(例如class名称、path路径、properties配置等),进一步减少了开发量。
常用到的注解有:

@ConditionalOnBean**(仅仅在当前上下文中存在某个对象时,才会实例化一个Bean)
@ConditionalOnClass(某个class位于类路径上,才会实例化一个Bean)
@ConditionalOnExpression(当表达式为true的时候,才会实例化一个Bean)
@ConditionalOnMissingBean(仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean)
@ConditionalOnMissingClass(某个class类路径上不存在的时候,才会实例化一个Bean)
@ConditionalOnNotWebApplication(不是web应用)

具体的用法可以参考前言中的文章

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郭Albert

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值