Conditional注解原理

比如@ConditionalOnBean注解

  1. @Target({ ElementType.TYPE, ElementType.METHOD })
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Conditional(OnBeanCondition.class)
  5. public @interface ConditionalOnBean {



在这个注解里面有OnBeanCondition类,OnBeanCondition继承了FilteringSpringBootCondition又继承了SpringBootCondition


ConfigurationClassParser#processConfigurationClass的
ConditionEvaluator#shouldSkip(AnnotatedTypeMetadata, ConfigurationPhase)

shouldSkip这个类的作用是 给扫描的类是否变成BeanDefinition对象,如果返回为true就说明这个类不需要实例化.

  1. /**
  2. * 确定是否应基于以下内容跳过项目 {@code @Conditional} 注解们.
  3. * @param metadata the meta data
  4. * @param phase the phase of the call
  5. * @return 是否应跳过该项目
  6. */
  7. public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
  8. //不存在@Conditional注解说明不需要判断,直接就实例化
  9. if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
  10. return false;
  11. }
  12. //下面是存在@Conditional注解的值
  13. if (phase == null) {
  14. if (metadata instanceof AnnotationMetadata &&
  15. ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
  16. return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
  17. }
  18. return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
  19. }
  20. //获取类上面的@Conditional
  21. List<Condition> conditions = new ArrayList<>();
  22. for (String[] conditionClasses : getConditionClasses(metadata)) {
  23. for (String conditionClass : conditionClasses) {
  24. Condition condition = getCondition(conditionClass, this.context.getClassLoader());
  25. conditions.add(condition);
  26. }
  27. }
  28. AnnotationAwareOrderComparator.sort(conditions);
  29. for (Condition condition : conditions) {
  30. ConfigurationPhase requiredPhase = null;
  31. if (condition instanceof ConfigurationCondition) {
  32. requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
  33. }
  34. //matches会调用到SpringBootCondition的matches
  35. if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
  36. return true;
  37. }
  38. }
  39. return false;
  40. }



注意看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

  1. @Target({ ElementType.TYPE, ElementType.METHOD })
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Conditional(OnClassCondition.class)
  5. 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 onClasses = getCandidates(metadata, ConditionalOnClass.class);
if (onClasses != null) {
// 核心方法,过滤一下,其实就是Class.forname一下ConditionalOnClass注解中的类,如果有异常就说明
// 上下文中没这个类,没有就过滤掉
List 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 onMissingClasses = getCandidates(metadata, ConditionalOnMissingClass.class);
if (onMissingClasses != null) {
List 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);
}


比如说@ConditionalOnBean

  1. @Target({ ElementType.TYPE, ElementType.METHOD })
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Conditional(OnBeanCondition.class)
  5. public @interface ConditionalOnBean {



就看OnBeanCondition类的org.springframework.boot.autoconfigure.condition.OnBeanCondition#getMatchOutcome 方法