Spring @Conditional条件匹配

Spring @Conditional指定条件匹配

1.指示只有在所有指定条件匹配时,组件才有资格注册。
2.条件是在注册bean定义之前可以通过编程确定的任何状态。
@Conditional注释可以以以下任何方式使用:

  • 作为任何直接或间接用@Component注释的类的类型级注释,包括@Configuration类
  • 作为元注释,用于编写自定义的构造型注释
  • 作为任何@Bean方法上的方法级注释
  • 如果@Configuration类用@Conditional标记,则与该类关联的所有@Bean方法、@Import 和@ComponentScan annotations都将受到这些条件的约束。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {

	/**
	 * 要注册组件,必须匹配的所有Condition类。
	 */
	Class<? extends Condition>[] value();

}

Condition 为了注册组件,必须匹配的单个条件。
在注册bean定义之前立即检查条件,并且可以根据此时可以确定的任何标准自由否决注册。
条件必须遵循与BeanFactoryPostProcessor相同的限制,并注意永远不要与bean实例交互。为了对与{@Configuration} beans交互的条件进行更细粒度的控制,请考虑实现ConfigurationCondition接口。

@FunctionalInterface
public interface Condition {

	/**
	 *确定条件是否匹配
	 */
	boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);

}

当与@Configuration一起使用时,提供更细粒度控制的Condition。允许某些条件在匹配时根据配置阶段进行调整。例如,检查bean是否已经注册的条件可能选择仅在REGISTER_bean ConfigurationCondition.ConfigurationPhase期间进行评估。

public interface ConfigurationCondition extends Condition {

	/**
	 * 返回应在其中评估条件的ConfigurationCondition.ConfigurationPhase
	 */
	ConfigurationPhase getConfigurationPhase();


	/**
	 * .可以评估条件的各种配置阶段
	 */
	enum ConfigurationPhase {

		/**
		 * 应在解析@Configuration类时评估Condition。
         * 如果此时条件不匹配,则不会添加@Configuration类。
		 */
		PARSE_CONFIGURATION,

		/**
		 * 在添加常规(非@Configuration)bean时,应该评估Condition。
		 * 该条件不会阻止添加@Configuration类。
         * 在评估条件时,所有@Configuration类都将被解析。
		 */
		REGISTER_BEAN
	}

}

ConditionEvaluator 用于评估条件

class ConditionEvaluator {

	private final ConditionContextImpl context;

	/**
	 * Create a new {@link ConditionEvaluator} instance.
	 */
	public ConditionEvaluator(@Nullable BeanDefinitionRegistry registry,
			@Nullable Environment environment, @Nullable ResourceLoader resourceLoader) {

		this.context = new ConditionContextImpl(registry, environment, resourceLoader);
	}


	/**
	 * 根据@Conditional注释确定是否应跳过项目。ConfigurationCondition.ConfigurationPhase将从项目类型中推导出来
	 * (即@Configuration类将为ConfigurationCondition.ConfigurationPhase.PARSE_Configuration)
	 */
	public boolean shouldSkip(AnnotatedTypeMetadata metadata) {
		return shouldSkip(metadata, null);
	}

	/**
	 *根据@Conditional注释确定是否应跳过项目
	 */
	public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
	//注释元数据是否为null 
	//元数据是否包含Conditional注解
		if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
			return false;
		}
      //判断是否为为阶段性校验匹配
		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<>();
		//所有condition类限定符名称
		for (String[] conditionClasses : getConditionClasses(metadata)) {
			for (String conditionClass : conditionClasses) {
			//反射创建condition
				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();
			}
			//
			if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
				return true;
			}
		}

		return false;
	}

	@SuppressWarnings("unchecked")
	private List<String[]> getConditionClasses(AnnotatedTypeMetadata metadata) {
		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());
	}

	private Condition getCondition(String conditionClassName, @Nullable ClassLoader classloader) {
		Class<?> conditionClass = ClassUtils.resolveClassName(conditionClassName, classloader);
		return (Condition) BeanUtils.instantiateClass(conditionClass);
	}


	
	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;

		public ConditionContextImpl(@Nullable BeanDefinitionRegistry registry,
				@Nullable Environment environment, @Nullable ResourceLoader resourceLoader) {

			this.registry = registry;
			this.beanFactory = deduceBeanFactory(registry);
			this.environment = (environment != null ? environment : deduceEnvironment(registry));
			this.resourceLoader = (resourceLoader != null ? resourceLoader : deduceResourceLoader(registry));
			this.classLoader = deduceClassLoader(resourceLoader, this.beanFactory);
		}

		@Nullable
		private ConfigurableListableBeanFactory deduceBeanFactory(@Nullable BeanDefinitionRegistry source) {
			if (source instanceof ConfigurableListableBeanFactory) {
				return (ConfigurableListableBeanFactory) source;
			}
			if (source instanceof ConfigurableApplicationContext) {
				return (((ConfigurableApplicationContext) source).getBeanFactory());
			}
			return null;
		}

		private Environment deduceEnvironment(@Nullable BeanDefinitionRegistry source) {
			if (source instanceof EnvironmentCapable) {
				return ((EnvironmentCapable) source).getEnvironment();
			}
			return new StandardEnvironment();
		}

		private ResourceLoader deduceResourceLoader(@Nullable BeanDefinitionRegistry source) {
			if (source instanceof ResourceLoader) {
				return (ResourceLoader) source;
			}
			return new DefaultResourceLoader();
		}

		@Nullable
		private ClassLoader deduceClassLoader(@Nullable ResourceLoader resourceLoader,
				@Nullable ConfigurableListableBeanFactory beanFactory) {

			if (resourceLoader != null) {
				ClassLoader classLoader = resourceLoader.getClassLoader();
				if (classLoader != null) {
					return classLoader;
				}
			}
			if (beanFactory != null) {
				return beanFactory.getBeanClassLoader();
			}
			return ClassUtils.getDefaultClassLoader();
		}

		@Override
		public BeanDefinitionRegistry getRegistry() {
			Assert.state(this.registry != null, "No BeanDefinitionRegistry available");
			return this.registry;
		}

		@Override
		@Nullable
		public ConfigurableListableBeanFactory getBeanFactory() {
			return this.beanFactory;
		}

		@Override
		public Environment getEnvironment() {
			return this.environment;
		}

		@Override
		public ResourceLoader getResourceLoader() {
			return this.resourceLoader;
		}

		@Override
		@Nullable
		public ClassLoader getClassLoader() {
			return this.classLoader;
		}
	}

}

比如在以下类中使用 ConditionEvaluator

  • ConfigurationClassBeanDefinitionReader
  • AnnotatedBeanDefinitionReader
  • ClassPathScanningCandidateComponentProvider
  • ConfigurationClassParser

ConfigurationClassUtils

private static final Set<String> candidateIndicators = new HashSet<>(8);

	static {
		candidateIndicators.add(Component.class.getName());
		candidateIndicators.add(ComponentScan.class.getName());
		candidateIndicators.add(Import.class.getName());
		candidateIndicators.add(ImportResource.class.getName());
	}
public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
		// Do not consider an interface or an annotation...
		if (metadata.isInterface()) {
			return false;
		}

		// Any of the typical annotations found?
		for (String indicator : candidateIndicators) {
			if (metadata.isAnnotated(indicator)) {
				return true;
			}
		}

		// Finally, let's look for @Bean methods...
		return hasBeanMethods(metadata);
	}

	static boolean hasBeanMethods(AnnotationMetadata metadata) {
		try {
			return metadata.hasAnnotatedMethods(Bean.class.getName());
		}
		catch (Throwable ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);
			}
			return false;
		}
	}

基于@Profile注释的值匹配的条件。

class ProfileCondition implements Condition {

	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
		if (attrs != null) {
			for (Object value : attrs.get("value")) {
				if (context.getEnvironment().acceptsProfiles(Profiles.of((String[]) value))) {
					return true;
				}
			}
			return false;
		}
		return true;
	}

}

更多的条件注解在Spring Boot中大量定义使用;

在这里插入图片描述
每个条件注解的详细解析请查看对应文章比如Spring Boot 条件注解-@ConditionalOnBean | ConditionalOnMissingBean

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值