<>@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 注解的处理 逻辑同上