【源码】Spring —— Condition 条件匹配解读

【源码】Spring —— Condition 条件匹配解读

前言

在注册 BeanDefinition 之前,会根据其 @Conditional 注解的条件进行过滤,@Conditional 是个 Spring内部用户自定义 bean 之间依赖关系很实用的一个注解,该章节解读 Condition条件匹配 的相关类

版本

Spring 5.2.x

ConditionEvaluator

仅限 Spring内部 使用的类,判断目标 BeanDefinition 是否应该跳过注册

目标 BeanDefinition上下文环境 由其内部类 ConditionContextImpl 维护

ConditionContextImpl

	private static class ConditionContextImpl implements ConditionContext {

		@Nullable
		private final BeanDefinitionRegistry registry;

		@Nullable
		private final ConfigurableListableBeanFactory beanFactory;

		private final Environment environment;

		private final ResourceLoader resourceLoader;

		@Nullable
		private final ClassLoader classLoader;

		// 略

	}

维护了 BeanDefinitionRegistryConfigurableListableBeanFactory 等相关 上下文属性

shouldSkip

	public boolean shouldSkip(AnnotatedTypeMetadata metadata) {
		return shouldSkip(metadata, null);
	}

	public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {

		// 必须被 Conditional 注解标注
		if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
			return false;
		}

		// 分析给定 metadata 的 ConfigurationPhase
		if (phase == null) {
			if (metadata instanceof AnnotationMetadata &&
					ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
				return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
			}
			return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
		}

		List<Condition> conditions = new ArrayList<>();

		// 此处 getConditionClasses 方法返回的是所有 Conditional 注解的 value 属性  
		for (String[] conditionClasses : getConditionClasses(metadata)) {
			for (String conditionClass : conditionClasses) {
				Condition condition = getCondition(conditionClass, this.context.getClassLoader());
				conditions.add(condition);
			}
		}

		// 排序
		AnnotationAwareOrderComparator.sort(conditions);

		// 调用所有 Condition 的 match 方法进行匹配
		// 有一个不匹配则返回 true,即 shouldSkip(应该跳过注册目标 BeanDefinition)
		for (Condition condition : conditions) {
			ConfigurationPhase requiredPhase = null;
			if (condition instanceof ConfigurationCondition) {
				requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
			}

			// 过滤对应 ConfigurationPhase 的 Condition
			if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
				return true;
			}
		}

		return false;
	}

	------------------- getConditionClasses -------------------

	@SuppressWarnings("unchecked")
	private List<String[]> getConditionClasses(AnnotatedTypeMetadata metadata) {
		/**
		 * getAllAnnotationAttributes 方法会追溯所有的注解
		 * 换句话说,即便定义在其注解下(例如 ConditionalOnXXX)
		 * 		也是可以追溯到并合并其属性的
		 */
		MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(Conditional.class.getName(), true);
		Object values = (attributes != null ? attributes.get("value") : null);
		return (List<String[]>) (values != null ? values : Collections.emptyList());
	}

	---------------------- getCondition ----------------------

	// 返回指定的 Condition 实例
	private Condition getCondition(String conditionClassName, @Nullable ClassLoader classloader) {
		Class<?> conditionClass = ClassUtils.resolveClassName(conditionClassName, classloader);
		return (Condition) BeanUtils.instantiateClass(conditionClass);
	}

具体的细节给出了详细的注释,这里总结一下大体流程

整个方法可以理解为一个简单的 递归

方法会在第一次 shouldSkip 判断目标 BeanDefinitionConfigurationPhase 类型

再次进入 shouldSkip 方法,获取对应 @Conditional 注解上 value 属性的值,解析并获取对应的 Condition 实例,再以 ConfigurationPhase 过滤后,执行 match 方法检测条件是否匹配

但凡有一个 Condition 不匹配,则返回 true,标识该 BeanDefinition 跳过注册

ConfigurationPhase

public interface ConfigurationCondition extends Condition {

	ConfigurationPhase getConfigurationPhase();

	enum ConfigurationPhase {

		PARSE_CONFIGURATION,

		REGISTER_BEAN
	}
}

---------------------Condition--------------------------

@FunctionalInterface
public interface Condition {

	boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);

}

ConfigurationPhaseCondition 的子接口 ConfigurationCondition 的一个内部 枚举类,定义了两种 Condition

  • PARSE_CONFIGURATION:表明该类 Condition 在解析 @Configuration 时检测匹配
  • REGISTER_BEAN:表明该类 Condition 在注册 普通Bean 时检测匹配

总结

匹配 @Conditional 注解条件的 BeanDefinition 才有机会被注册,Spring内部 大量的使用了该注解来维护 bean 之间的依赖关系,我们平时的开发工作中也避免不了频繁的使用

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值