Conditional注解原理
比如@ConditionalOnBean注解
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnBean {
在这个注解里面有OnBeanCondition类,OnBeanCondition继承了FilteringSpringBootCondition又继承了SpringBootCondition
ConfigurationClassParser#processConfigurationClass的
ConditionEvaluator#shouldSkip(AnnotatedTypeMetadata, ConfigurationPhase)
shouldSkip这个类的作用是 给扫描的类是否变成BeanDefinition对象,如果返回为true就说明这个类不需要实例化.
/**
* 确定是否应基于以下内容跳过项目 {@code @Conditional} 注解们.
* @param metadata the meta data
* @param phase the phase of the call
* @return 是否应跳过该项目
*/
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
//不存在@Conditional注解说明不需要判断,直接就实例化
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}
//下面是存在@Conditional注解的值
if (phase == null) {
if (metadata instanceof AnnotationMetadata &&
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
}
return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
}
//获取类上面的@Conditional
List<Condition> conditions = new ArrayList<>();
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
conditions.add(condition);
}
}
AnnotationAwareOrderComparator.sort(conditions);
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
//matches会调用到SpringBootCondition的matches
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
return true;
}
}
return false;
}
注意看org.springframework.context.annotation.Condition#matches方法,这行方法会调用到SpringBootCondition类的matches方法
@Override public final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { String classOrMethodName = getClassOrMethodName(metadata); try { // 典型的钩子方法,调到用具体子类中方法。ConditionOutcome 这个类里面包装了是否需 // 跳过和打印的日志 //获取匹配结果.boolean类型的, @conditional 注解解析过程 ConditionOutcome outcome = getMatchOutcome(context, metadata); logOutcome(classOrMethodName, outcome); recordEvaluation(context, classOrMethodName, outcome); return outcome.isMatch(); } catch (NoClassDefFoundError ex) { throw new IllegalStateException(“Could not evaluate condition on “ + classOrMethodName + “ due to “ + ex.getMessage() + “ not found. Make sure your own configuration does not rely on “ + “that class. This can also happen if you are “ + “@ComponentScanning a springframework package (e.g. if you “ + “put a @ComponentScan in the default package by mistake)”, ex); } catch (RuntimeException ex) { throw new IllegalStateException(“Error processing condition on “ + getName(metadata), ex); } } |
---|
注意看getMatchOutcome方法.这个方法会去解析各种的@Conditional注解
比如说@ConditionalOnClass
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {
就看org.springframework.boot.autoconfigure.condition.OnClassCondition#getMatchOutcome方法
@Override public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { ClassLoader classLoader = context.getClassLoader(); ConditionMessage matchMessage = ConditionMessage.empty(); List if (onClasses != null) { // 核心方法,过滤一下,其实就是Class.forname一下ConditionalOnClass注解中的类,如果有异常就说明 // 上下文中没这个类,没有就过滤掉 List 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 if (onMissingClasses != null) { List 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); } |
---|
比如说@ConditionalOnBean
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnBean {
就看OnBeanCondition类的org.springframework.boot.autoconfigure.condition.OnBeanCondition#getMatchOutcome 方法