@Conditional
满足指定条件的时候才将某个 bean 加载到应用上下文中.
比如 FreemarkerAutoConfiguration 这个自动化配置类的定义如下:
1 2 3 4 5 6 7
| @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 包下.
1 2 3 4 5 6 7 8 9 10 11 12 13
| ConditionalOnBean ConditionalOnClass ConditionalOnCloudPlatform ConditionalOnExpression ConditionalOnJava ConditionalOnJndi ConditionalOnMissingBean ConditionalOnMissingClass ConditionalOnNotWebApplication ConditionalOnProperty ConditionalOnResource ConditionalOnSingleCandidate ConditionalOnWebApplication
|
1 2 3 4 5 6 7
| @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Conditional(OnBeanCondition.class) public @interface ConditionalOnBean { }
|
spring-boot Condition 注解对应处理的 Conditional 类
1 2 3 4 5 6 7
| 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
调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { ClassLoader classLoader = context.getClassLoader(); ConditionMessage matchMessage = ConditionMessage.empty(); List<String> onClasses = getCandidates(metadata, ConditionalOnClass.class); if (onClasses != null) { List<String> missing = filter(onClasses, ClassNameFilter.MISSING, classLoader); if (!missing.isEmpty()) { return ConditionOutcome .noMatch(ConditionMessage.forCondition(ConditionalOnClass.class) .didNotFind("required class", "required classes") .items(Style.QUOTE, missing)); } matchMessage = matchMessage.andCondition(ConditionalOnClass.class) .found("required class", "required classes").items(Style.QUOTE, filter(onClasses, ClassNameFilter.PRESENT, classLoader)); } List<String> onMissingClasses = getCandidates(metadata, ConditionalOnMissingClass.class); 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); }
|
1 2 3 4 5 6 7
| 对 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 注解的处理 逻辑同上
|