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);}//获取类上面的@ConditionalList<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的matchesif ((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 方法
