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