栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

@Conditional && Condition

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

@Conditional && Condition

一、条件注解@Conditional

@Conditional是Spring4.0提供的一个用于条件装配的注解,其定义了一个Condition的数组,只有当数组所有的条件都满足的时候,组件才会被导入容器。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {

	
	Class[] value();

}

@Conditional注解可以有两种使用方法:

  1. 类型级别,任意直接或者间接标注了@Conponent注解的类或者注解,比如@Configuration或者@Profile
  2. 方法级别,任意标注了@Bean注解的方法

如果一个@Configuration类标注了@Conditional,那么这个类所有的@Bean方法,@ComponentScan和@Import的结果都受@Conditional注解的条件约束。
特别要注意的是:@Conditional是不支持继承的,任何父类的条件注解或者方法继承的条件注解都不会生效。为了强化这些语义,@Conditional本身并没有标注@Inherited。另外,任何使用了@Conditional注解的组合注解都不能声明为@Inherited。

二、条件判断接口Condition

@Conditional注解依赖于Condition接口,该接口提供真正的条件判断逻辑。

public interface Condition {

	
	boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);

}

Condition接口传递两个参数ConditionContext和AnnotatedTypeMetadata,在Condition实现类中可以直接使用这两个参数,获取环境、容器、类等相关信息。

1. ConditionContext
public interface ConditionContext {

	
	BeanDefinitionRegistry getRegistry();

	
	ConfigurableListableBeanFactory getBeanFactory();

	
	Environment getEnvironment();

	
	ResourceLoader getResourceLoader();

	
	ClassLoader getClassLoader();

}

CondtitionContext可以获取到BeanDefinitionRegistry、ConfigurableListableBeanFactory、Environment、ResourceLoader、ClassLoader这些环境相关的信息。

2. AnnotatedTypeMetadata

参考 类和方法元信息、注解信息体系(AnnotatedTypeMetadata、AnnotationMetadata、ClassMetadata、MethodMetadata)
可以获取类及相关注解的相关信息。

三、@Conditional如何被解析,Condition方法何时调用?

@Conditional和Condition的相关逻辑是在类ConditionEvaluator#中实现的。

class ConditionEvaluator {

	private final ConditionContextImpl context;


	
	public ConditionEvaluator(BeanDefinitionRegistry registry, Environment environment, ResourceLoader resourceLoader) {
		this.context = new ConditionContextImpl(registry, environment, resourceLoader);
	}


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

	
	public boolean shouldSkip(AnnotatedTypeMetadata metadata, ConfigurationPhase phase) {
		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 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();
			}
			if (requiredPhase == null || requiredPhase == phase) {
				if (!condition.matches(this.context, metadata)) {
					return true;
				}
			}
		}

		return false;
	}

	@SuppressWarnings("unchecked")
	private List getConditionClasses(AnnotatedTypeMetadata metadata) {
		MultiValueMap attributes = metadata.getAllAnnotationAttributes(Conditional.class.getName(), true);
		Object values = (attributes != null ? attributes.get("value") : null);
		return (List) (values != null ? values : Collections.emptyList());
	}

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


	
	private static class ConditionContextImpl implements ConditionContext {

		private final BeanDefinitionRegistry registry;

		private final ConfigurableListableBeanFactory beanFactory;

		private final Environment environment;

		private final ResourceLoader resourceLoader;

		public ConditionContextImpl(BeanDefinitionRegistry registry, Environment environment, ResourceLoader resourceLoader) {
			this.registry = registry;
			this.beanFactory = deduceBeanFactory(registry);
			this.environment = (environment != null ? environment : deduceEnvironment(registry));
			this.resourceLoader = (resourceLoader != null ? resourceLoader : deduceResourceLoader(registry));
		}

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

		private Environment deduceEnvironment(BeanDefinitionRegistry source) {
			if (source instanceof EnvironmentCapable) {
				return ((EnvironmentCapable) source).getEnvironment();
			}
			return null;
		}

		private ResourceLoader deduceResourceLoader(BeanDefinitionRegistry source) {
			if (source instanceof ResourceLoader) {
				return (ResourceLoader) source;
			}
			return null;
		}

		@Override
		public BeanDefinitionRegistry getRegistry() {
			return this.registry;
		}

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

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

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

		@Override
		public ClassLoader getClassLoader() {
			if (this.resourceLoader != null) {
				return this.resourceLoader.getClassLoader();
			}
			if (this.beanFactory != null) {
				return this.beanFactory.getBeanClassLoader();
			}
			return null;
		}
	}

}

而该类根据构造方法的调用点,可知以下几个类会使用到。

  • AnnotatedBeanDefinitionReader 注解标注时候
  • ClassPathScanningCandidateComponentProvider注解扫描时候
  • ConfigurationClassBeanDefinitionReader、ConfigurationClassParser(ConfigurationClassPostProcessor) 解析Configuration注解的过程中
四、典型应用 @Profile

@Profile就是典型地基于@Conditional的扩展,其条件逻辑封装在ProfileCondition中

class ProfileCondition implements Condition {

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

}
Springboot中的应用

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/872205.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号