springboot conditional 注解

@Conditional

满足指定条件的时候才将某个 bean 加载到应用上下文中.

比如 FreemarkerAutoConfiguration 这个自动化配置类的定义如下:

@ConditionalOnClass(ThreadPoolTaskScheduler.class)
@Configuration
@EnableConfigurationProperties(TaskSchedulingProperties.class)
@AutoConfigureAfter(TaskExecutionAutoConfiguration.class)
public class TaskSchedulingAutoConfiguration {
    // ...
}

这个自动化配置类被 @ConditionalOnClass 条件注解修饰,

这个条件注解存在的意义在于判断类加载器中是否存在 ThreadPoolTaskScheduler 这个类,

如果存在的话会在 Spring 容器中加载这个 TaskSchedulingAutoConfiguration 配置类, 否则不会加载.

@ConditionalOnXxxx

Spring Boot 在 @Conditional 注解的基础上进行了细化,无需自己实现 Condition 接口,只需要使用预定义好的 @ConditionalOnXxxx 类,如果验证通过,就会注册对应的 bean.

这些注解都定义在 org.springframework.boot.autoconfigure.condition 包下.

ConditionalOnBean
ConditionalOnClass
ConditionalOnCloudPlatform
ConditionalOnExpression
ConditionalOnJava
ConditionalOnJndi
ConditionalOnMissingBean
ConditionalOnMissingClass
ConditionalOnNotWebApplication
ConditionalOnProperty
ConditionalOnResource
ConditionalOnSingleCandidate
ConditionalOnWebApplication
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnBean {
    // ...
}

spring-boot Condition 注解对应处理的 Conditional 类

Condition (org.springframework.context.annotation)
    ConfigurationCondition (org.springframework.context.annotation)
        AbstractNestedCondition (org.springframework.boot.autoconfigure.condition)
        AllNestedConditions (org.springframework.boot.autoconfigure.condition)
        NoneNestedConditions (org.springframework.boot.autoconfigure.condition)
        AnyNestedCondition (org.springframework.boot.autoconfigure.condition)
        OnBeanCondition (org.springframework.boot.autoconfigure.condition)

Condition 接口

ConfigurationCondition 接口

多了一个 getConfigurationPhase() 方法, 也就是 条件注解的生效阶段. 只有在 ConfigurationPhase 中定义的两种阶段下才会生效.

SpringBootCondition

SpringBoot 中所有条件注解对应的条件类都继承这个抽象类.

OnClassCondition

@ConditionalOnClass 或者 @ConditionalOnMissingClass 注解对应的条件类是 OnClassCondition

入口

1.ComponentScan 扫描 basePackage 下的 components 的时候, 会调用 isConditionMatch(metadataReader) 判断该 component 是否条件匹配. 通过调用 conditionEvaluator.shouldSkip(metadataReader.getAnnotationMetadata()) 判断是否要 skip 该 component.
2.// TODO

调用

conditionEvaluator.shouldSkip()
1. 判断必须有 @Conditional 注解
2. 判断是否有 phase
3. 通过 metadata 获取该类上的所有 Conditional 注解
4. 遍历通过 conditionClassName 获取对应的 Condition 类
5. 对 conditions 排序
6. 遍历 conditions, 若是 ConfigurationCondition 类型, 调用 getConfigurationPhase() 方法, 调用 condition.matches() 方法
    SpringBootCondition.matches()
    1.getClassOrMethodName() 从 metadata 中获取类名或者方法名 (条件注解可以作用的类或者方法上)
    2.getMatchOutcome(): 抽象方法, 具体子类实现. ConditionOutcome 记录了匹配结果 和 log 信息
        由具体的 Condition 接口的实现类实现该逻辑, 如 OnClassCondition, OnExpressionCondition 等
        // OnClassCondition.getMatchOutcome() 参见 下面逻辑
    3.logOutcome(): 打印 匹配信息 日志
    4.recordEvaluation(): 记录 匹配信息 结果
    5.outcome.isMatch(): 返回是否匹配结果

OnClassCondition.getMatchOutcome()

public ConditionOutcome getMatchOutcome(ConditionContext context,
        AnnotatedTypeMetadata metadata) {
    ClassLoader classLoader = context.getClassLoader();
    ConditionMessage matchMessage = ConditionMessage.empty();
    List<String> onClasses = getCandidates(metadata, ConditionalOnClass.class); // 1.ConditionalOnClass 注解处理. 获取类上 @ConditionalOnClass 注解里的条件值. 如从 @ConditionalOnClass({ Servlet.class, ServerContainer.class }) 中获取 Servlet.class, ServerContainer.class
    if (onClasses != null) {
        List<String> missing = filter(onClasses, ClassNameFilter.MISSING,
                classLoader); // 判断条件类是否存在, 不存在的添加到 missing 里
        if (!missing.isEmpty()) { // 有不存在的条件
            return ConditionOutcome
                    .noMatch(ConditionMessage.forCondition(ConditionalOnClass.class)
                            .didNotFind("required class", "required classes")
                            .items(Style.QUOTE, missing)); // 不匹配 condition
        }
        matchMessage = matchMessage.andCondition(ConditionalOnClass.class)
                .found("required class", "required classes").items(Style.QUOTE,
                        filter(onClasses, ClassNameFilter.PRESENT, classLoader)); // 匹配 condition
    }
    List<String> onMissingClasses = getCandidates(metadata,
            ConditionalOnMissingClass.class); // 2. ConditionalOnMissingClass 注解处理
    if (onMissingClasses != null) {
        List<String> present = filter(onMissingClasses, ClassNameFilter.PRESENT,
                classLoader);
        if (!present.isEmpty()) {
            return ConditionOutcome.noMatch(
                    ConditionMessage.forCondition(ConditionalOnMissingClass.class)
                            .found("unwanted class", "unwanted classes")
                            .items(Style.QUOTE, present));
        }
        matchMessage = matchMessage.andCondition(ConditionalOnMissingClass.class)
                .didNotFind("unwanted class", "unwanted classes")
                .items(Style.QUOTE, filter(onMissingClasses, ClassNameFilter.MISSING,
                        classLoader));
    }
    return ConditionOutcome.match(matchMessage);
}
对 ConditionalOnClass 和 ConditionalOnMissingClass 注解的处理.
1. 对 ConditionalOnClass 注解的处理
    1. 获取类上 @ConditionalOnClass 注解里的条件值. 如从 @ConditionalOnClass({Servlet.class, ServerContainer.class}) 中获取 Servlet.class, ServerContainer.class
    2.filter(onClasses, ClassNameFilter.MISSING, classLoader) 通过 ter.MISSING 这个 filter 过滤出不存在的类 (即通过 classLoader 加载不到)
    3. 返回是否匹配结果
2. 对 ConditionalOnMissingClass 注解的处理
    逻辑同上
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

FlyingZCC

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

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

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

打赏作者

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

抵扣说明:

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

余额充值