有一篇文章:《Spring Boot @Condition 注解,组合条件你知道吗》十分值得阅读
@Conditional注解可以作用在创建Bean的类或者方法上,给Spring容器是否加载此bean,添加额外的约束或者判断。
作用在:
类注解(@Component、@Controller、@Service、@Repository)方法注解(@Bean)的bean都可以用@Conditional做额外约束
当@Conditional注解的判断条件不满足时,对应的Bean不会生成。
根据上面的介绍,我们知道@Conditional注解是来让Spring容器选择是否加载对应bean的。也就是Spring可以通过**“某种判断”,来确定结果是true或false,进而决定是否加载此bean。 在具体的实现上,“这个判断”**是通过程序员实现Condition接口并重写public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata)方法来实现的。
编写一个我们自己的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; } }在创建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; } }从上面的例子可以看到,@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应用)
具体的用法可以参考前言中的文章