Spring @Conditional

目录

 

@Conditional的使用

其他派生注解

源码解析

@Conditional

加载流程

ConditionEvaluator

Spring boot派生注解

@ConditionalOnBean

@ConditionalOnMissingBean

@ConditionalOnClass

@ConditionalOnMissingClass

@ConditionalOnCloudPlatform

@ConditionalOnExpression

@ConditionalOnJava

@ConditionalOnJndi

@ConditionalOnNotWebApplication

@ConditionalOnProperty

@ConditionalOnResource

@ConditionalOnSingleCandidate

@ConditionalOnWebApplication

Condition实现类

ConfigurationCondition

SpringBootCondition

FilteringSpringBootCondition 

OnClassCondition 


@Conditional的使用

  • 作用:根据条件,决定类是否加载到Spring Ioc容器中
  • 应用场景:在一些需要条件满足才实例化的类上使用此注解

其他派生注解

  • @ConditionalOnMissingBean

​ 只有对应的bean在系统中都没有被创建,它注解的初始化代码块才会执行,用户自己手动创建的bean优先

  • @ConditionalOnBean

仅仅在当前上下文中存在某个对象时,才会实例化一个Bean。

  • @ConditionalOnClass

​ 某个class位于类路径上,才会实例化一个Bean

  • @ConditionalOnExpression

​ 当表达式为true的时候,才会实例化一个Bean。

  • @ConditionalOnMissingClass

某个class类路径上不存在的时候,才会实例化一个Bean

  • @ConditionalOnNotWebApplication

​ 不是web应用

  • @ConditionalOnProperty

当属性满足条件时配置

//当 filter.loginFilter = true时生效
@ConditionalOnProperty(prefix = "filter",name = "loginFilter",havingValue = "true")

 

源码解析

@Conditional

public @interface Conditional {
	Class<? extends Condition>[] value();
}

value属性值必须是一组继承于Condition的类。在Condition类中只有一个方法matches方法。这类的作用是,在bean的定义即将被注册之前,会检查条件是否匹配,然后根据匹配的结果决定是否注册bean。

@FunctionalInterface
public interface Condition {
	/**
	 * 判断是否满足条件
	 */
	boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

ConditionContext封装了IOC容器的信息。

public interface ConditionContext {
	BeanDefinitionRegistry getRegistry();
	@Nullable
	ConfigurableListableBeanFactory getBeanFactory();
	Environment getEnvironment();
	ResourceLoader getResourceLoader();
	@Nullable
	ClassLoader getClassLoader();
}

加载流程

通过查看Condition的matches在哪里被调用。发现整个spring中只有在ConditionEvaluator中调用了这个方法。这个类的作用是评估一个贴了Conditional注解的类是否需要跳过。通过类上面的注解来判断。此方法的调用是由ConfigurationClassPostProcessor引起的,用于处理@Configuration的解析(参考:SpringBoot启动流程)。

//ConfigurationClassPostProcessor:
	protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
		if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
			return;
		}
    }

ConditionEvaluator

   
    public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
        没有注解 @Conditional,则返回false,caller则继续处理。
		if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
			return false;
		}

		if (phase == null) {
            //bean的注解信息封装对象是AnnotationMetadata类型并且,类上有@Component,@ComponentScan,@Import,@ImportResource,则表示为配置类型(此处是一直往最原始的注解追溯)
			if (metadata instanceof AnnotationMetadata &&
					ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
				return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
			}
            
            //表示是配置是bean类型
			return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
		}

		List<Condition> conditions = new ArrayList<>();
        //从bean的注解信息封装对象中获取所有的Conditional类型或者Conditional的派生注解
		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) {
            //获取需要对bean进行的操作,是解析还是注册
				requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
			}
            
            //(如果requiredPhase==null或者指定的操作类型是目前阶段的操作类型)并且不符合设置的条件则跳过
			if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
				return true;
			}
		}

		return false;
	}

Spring boot派生注解

@ConditionalOnBean

@Conditional(OnBeanCondition.class)
public @interface ConditionalOnBean {
	Class<?>[] value() default {};
	String[] type() default {};
	Class<? extends Annotation>[] annotation() default {};
	String[] name() default {};
	SearchStrategy search() default SearchStrategy.ALL;
	Class<?>[] parameterizedContainer() default {};
}

@ConditionalOnMissingBean

@Conditional(OnBeanCondition.class)
public @interface ConditionalOnMissingBean {
	Class<?>[] value() default {};
	String[] type() default {};
	Class<?>[] ignored() default {};
	String[] ignoredType() default {};
	Class<? extends Annotation>[] annotation() default {};
	String[] name() default {};
	SearchStrategy search() default SearchStrategy.ALL;
	Class<?>[] parameterizedContainer() default {};
}

@ConditionalOnClass

@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {
	Class<?>[] value() default {};
	String[] name() default {};
}

@ConditionalOnMissingClass

@Conditional(OnClassCondition.class)
public @interface ConditionalOnMissingClass {
	String[] value() default {};
}

@ConditionalOnCloudPlatform

@Conditional(OnCloudPlatformCondition.class)
public @interface ConditionalOnCloudPlatform {
	CloudPlatform value();
}

@ConditionalOnExpression

@Conditional(OnExpressionCondition.class)
public @interface ConditionalOnExpression {
	String value() default "true";
}

@ConditionalOnJava

@Conditional(OnJavaCondition.class)
public @interface ConditionalOnJava {
	Range range() default Range.EQUAL_OR_NEWER;
	JavaVersion value();
	enum Range {
		EQUAL_OR_NEWER,
		OLDER_THAN
	}
}

@ConditionalOnJndi

@Conditional(OnJndiCondition.class)
public @interface ConditionalOnJndi {
	String[] value() default {};
}

@ConditionalOnNotWebApplication

@Conditional(OnWebApplicationCondition.class)
public @interface ConditionalOnNotWebApplication {

}

@ConditionalOnProperty

@Conditional(OnPropertyCondition.class)
public @interface ConditionalOnProperty {
	String[] value() default {};
	String prefix() default "";
	String[] name() default {};
	String havingValue() default "";
	boolean matchIfMissing() default false;
}

@ConditionalOnResource

@Conditional(OnResourceCondition.class)
public @interface ConditionalOnResource {

	String[] resources() default {};

}

@ConditionalOnSingleCandidate

@Conditional(OnBeanCondition.class)
public @interface ConditionalOnSingleCandidate {
	Class<?> value() default Object.class;
	String type() default "";
	SearchStrategy search() default SearchStrategy.ALL;
}

@ConditionalOnWebApplication

@Conditional(OnWebApplicationCondition.class)
public @interface ConditionalOnWebApplication {
	Type type() default Type.ANY;
	enum Type {
		ANY,
		SERVLET,
		REACTIVE
	}
}

Condition实现类

 

ConfigurationCondition

public interface ConfigurationCondition extends Condition {
	ConfigurationPhase getConfigurationPhase();
	enum ConfigurationPhase {
		PARSE_CONFIGURATION,
		REGISTER_BEAN
	}
}

SpringBootCondition


public abstract class SpringBootCondition implements Condition {

	private final Log logger = LogFactory.getLog(getClass());

	@Override
	public final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //从封装condition注解信息的类中获取指定的Condition类的实现类
		String classOrMethodName = getClassOrMethodName(metadata);
		try {
            //确定匹配结果以及日志输出对象
			ConditionOutcome outcome = getMatchOutcome(context, metadata);
			logOutcome(classOrMethodName, outcome);
            
            //将匹配结果进行存储
			recordEvaluation(context, classOrMethodName, outcome);
            //返回匹配的结果
			return outcome.isMatch();
		}
		catch (NoClassDefFoundError ex) {
			
		}
		catch (RuntimeException ex) {
			throw new IllegalStateException("Error processing condition on " + getName(metadata), ex);
		}
	}

	/**
	 *由子类实现
	 */
	public abstract ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata);

}

FilteringSpringBootCondition 

abstract class FilteringSpringBootCondition extends SpringBootCondition
		implements AutoConfigurationImportFilter, BeanFactoryAware, BeanClassLoaderAware {

	private BeanFactory beanFactory;

	private ClassLoader beanClassLoader;

	@Override
	public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
		ConditionEvaluationReport report = ConditionEvaluationReport.find(this.beanFactory);
		ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, autoConfigurationMetadata);
		boolean[] match = new boolean[outcomes.length];
		for (int i = 0; i < outcomes.length; i++) {
			match[i] = (outcomes[i] == null || outcomes[i].isMatch());
			if (!match[i] && outcomes[i] != null) {
				logOutcome(autoConfigurationClasses[i], outcomes[i]);
				if (report != null) {
					report.recordConditionEvaluation(autoConfigurationClasses[i], this, outcomes[i]);
				}
			}
		}
		return match;
	}

	protected abstract ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
			AutoConfigurationMetadata autoConfigurationMetadata);

} 

OnClassCondition 

OnClassCondition用于@ConditionalOnClass@ConditionalOnMissingClass


    @Override
	public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
		ClassLoader classLoader = context.getClassLoader();
		ConditionMessage matchMessage = ConditionMessage.empty();
        返回ConditionalOnClass的value,name属性的值列表,
		List<String> onClasses = getCandidates(metadata, ConditionalOnClass.class);
		if (onClasses != null) {
            返回未被加载的class列表。
			List<String> missing = filter(onClasses, ClassNameFilter.MISSING, classLoader);
			if (!missing.isEmpty()) {
            如果missling为空,表示没有匹配的,返回未匹配结果。
				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<String> onMissingClasses = getCandidates(metadata, ConditionalOnMissingClass.class);
		if (onMissingClasses != null) {
        返回所有加载的class列表
			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);
	}
    

 

发布了174 篇原创文章 · 获赞 21 · 访问量 2万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章