0
点赞
收藏
分享

微信扫一扫

Spring Boot @Conditional注解及条件实现

陬者 2022-02-27 阅读 47

Condition

条件满足返回true,条件不满足返回false

@FunctionalInterface
public interface Condition {
	boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

几个子接口、类

Condition有几个子接口、类,对其功能做了扩展

ConfigurationCondition

public interface ConfigurationCondition extends Condition {

	ConfigurationPhase getConfigurationPhase();

	enum ConfigurationPhase {
		PARSE_CONFIGURATION,
		REGISTER_BEAN
	}
}

ConfigurationCondition接口加了一个描述该Condition阶段的方法,只有调用Condition的阶段跟该Condition的阶段相匹配,matches方法才会被调用。ConfigurationPhase定义了两个阶段:
PARSE_CONFIGURATION:配置类( @Configuration)解析阶段
REGISTER_BEAN:普通bean的注册阶段(包括配置类的注册)

SpringBootConfiguration

public abstract class SpringBootCondition implements Condition {

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

	@Override
	public final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		String classOrMethodName = getClassOrMethodName(metadata);
		try {
			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);
		}
	}
}

SpringBootCondition是一个抽象类,使用模板模式实现了接口方法,做了三件事:
1、getMatchOutcome生成ConditionOutcome,是个抽象方法(唯一的一个需要子类实现的方法)
2、落日志,等级trace
3、调用ConditionEvaluationReport报告结果

ConditionOutcome记录了匹配结果和message

public class ConditionOutcome {

	private final boolean match;

	private final ConditionMessage message;
}

FilteringSpringBootCondition

类定义

abstract class FilteringSpringBootCondition extends SpringBootCondition
		implements AutoConfigurationImportFilter, BeanFactoryAware, BeanClassLoaderAware

FilteringSpringBootCondition扩展了SpringBootCondition,还实现了AutoConfigurationImportFilter接口。扩展SpringBootCondition接口并未实现其抽象方法,与SpringBootCondition完全一样;实现AutoConfigurationImportFilter接口部分需要看一下

AutoConfigurationImportFilter

@FunctionalInterface
public interface AutoConfigurationImportFilter {
	boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata);
}

AutoConfigurationImportFilter接口是干嘛的?SpringBoot会把AutoConfiguration配置类写在spring.factories文件里,会写的非常全,实际上工程里大部分都用不到,需要提前过滤掉一大部分。传进来的autoConfigurationClasses是需要过滤的类,返回boolean[]数组,即每个类条件是否match,为true则条件match,该AutoConfiguration类应保留;为false则条件不match,该AutoConfiguration类应过滤掉

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;
	}
}

FilteringSpringBootCondition实现了AutoConfigurationImportFilter接口的match方法,实际上也是采用模板模式,做了4件事情
1、调用抽象方法getOutcomes,获取每个自动配置类的ConditionOutcome数组
2、for循环里拼装返回结果:outcome是null或者outcome isMatch,这个类配置都match
3、记录日志
4、报告结果

这里再介绍这个类里面的一个重要方法filter,后面多处都在使用
filter方法会传进来一组类名classNames和classNameFilter,作用是返回满足classNameFilter条件的类

	protected final List<String> filter(Collection<String> classNames, ClassNameFilter classNameFilter,
			ClassLoader classLoader) {
		if (CollectionUtils.isEmpty(classNames)) {
			return Collections.emptyList();
		}
		List<String> matches = new ArrayList<>(classNames.size());
		for (String candidate : classNames) {
			if (classNameFilter.matches(candidate, classLoader)) {
				matches.add(candidate);
			}
		}
		return matches;
	}

ClassNameFilter是一个枚举,有PRESENT、MISSING两个
ClassNameFilter里isPresent方法就是调用Class.forName判断这个类是否存在,再看两个枚举实现的matches方法可以得知:枚举PRESENT当类存在时返回true,枚举MISSING当类不存在时返回true

	protected enum ClassNameFilter {

		PRESENT {

			@Override
			public boolean matches(String className, ClassLoader classLoader) {
				return isPresent(className, classLoader);
			}

		},

		MISSING {

			@Override
			public boolean matches(String className, ClassLoader classLoader) {
				return !isPresent(className, classLoader);
			}

		};

		abstract boolean matches(String className, ClassLoader classLoader);

		static boolean isPresent(String className, ClassLoader classLoader) {
			if (classLoader == null) {
				classLoader = ClassUtils.getDefaultClassLoader();
			}
			try {
				resolve(className, classLoader);
				return true;
			}
			catch (Throwable ex) {
				return false;
			}
		}
	}

	protected static Class<?> resolve(String className, ClassLoader classLoader) throws ClassNotFoundException {
		if (classLoader != null) {
			return Class.forName(className, false, classLoader);
		}
		return Class.forName(className);
	}

所以filter(Collection classNames, ClassNameFilter classNameFilter, ClassLoader classLoader)这个方法的用处就是:ClassNameFilter传PRESENT时,返回classNames中存在的类;ClassNameFilter传MISSING时,返回classNames中不存在的类

在哪里用

配置类解析&bean注册

1、ConfigurationClassParser#processConfigurationClass
ConfigurationClassParser在解析配置类时

	protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
		if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
			return;
		}
        ...
    }

2、ConfigurationClassParser#doProcessConfigurationClass处理配置类的ComponentScan注解时

protected final SourceClass doProcessConfigurationClass(
			ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
			throws IOException {
        ...
            
		// Process any @ComponentScan annotations
		Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
		if (!componentScans.isEmpty() &&
				!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
			for (AnnotationAttributes componentScan : componentScans) {
				// The config class is annotated with @ComponentScan -> perform the scan immediately
				Set<BeanDefinitionHolder> scannedBeanDefinitions =
						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
				// Check the set of scanned definitions for any further config classes and parse recursively if needed
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}
    
        ...
}

3、ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod注册@Bean时

	private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
        ...
            
		if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
			configClass.skippedBeanMethods.add(methodName);
			return;
		}
        ...
    }

4、AnnotatedBeanDefinitionReader#doRegisterBean注册bean时

	private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
			@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
			@Nullable BeanDefinitionCustomizer[] customizers) {

		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
		if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
			return;
		}
    }

这些使用场景都时借助ConditionEvaluator来调用Condition来获取match结果,主要是shouldSkip方法,返回true表示条件不满足,需要跳过该配置类或者不注册该bean

	public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
		if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
			return false;
		}

        // 1
		if (phase == null) {
			if (metadata instanceof AnnotationMetadata &&
					ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
				return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
			}
			return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
		}

        // 2
		List<Condition> conditions = new ArrayList<>();
		for (String[] conditionClasses : getConditionClasses(metadata)) {
			for (String conditionClass : conditionClasses) {
				Condition condition = getCondition(conditionClass, this.context.getClassLoader());
				conditions.add(condition);
			}
		}

        // 3
		AnnotationAwareOrderComparator.sort(conditions);

        // 4
		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;
	}

实现细节
1、如果phase为null,则推断当前的phase。如果该类是一个配置类,phase就是PARSE_CONFIGURATION,否则REGISTER_BEAN
怎么判断是不是一个配置类?其实就是看是否标了特定注解、是否有@bean方法

	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?
        // @Component、@ComponentScan、@Import、@ImportResource
		for (String indicator : candidateIndicators) {
			if (metadata.isAnnotated(indicator)) {
				return true;
			}
		}

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

2、获取Condition类并实例化
获取Condition类就是从@Conditional及其派生注解里获取到;实例化通过反射调用构造方法实现。一个配置类上或注册bean时,可能会指定多个条件,所有是一个List

3、对Condition进行排序
调用AnnotationAwareOrderComparator对Condition进行排序,AnnotationAwareOrderComparator能够将PriorityOrdered接口、Ordered接口、@Order指定的顺序都考虑进来

4、调用这一组条件

for循环调用这一组条件,调用条件前会判断phase是否匹配:如果condition未指定phase(直接实现Conditon接口而未实现ConfigurationConditon接口)或者condition的phase和当前phase相同,则会调用Condition接口。
并且只要有一个条件不满足,就会返回true,表明需要跳过该配置类或者不注册该bean;所有条件都满足,才会返回false

AutoConfiguration过滤自动配置类

AutoConfiguration的spring.factories里会写上很多自动配置类,实际工程中只会用到极少数,因此都读到的配置类会先过滤掉。主要逻辑在AutoConfigurationImportSelector#getAutoConfigurationEntry方法,getCandidateConfigurations(annotationMetadata, attributes)通过spring.factories spi获取到所有的AutoConfiguration类名称。下面看是如何过滤的

	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		configurations = removeDuplicates(configurations);
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

1、getConfigurationClassFilter()获取Filter

	private ConfigurationClassFilter getConfigurationClassFilter() {
		if (this.configurationClassFilter == null) {
			List<AutoConfigurationImportFilter> filters = getAutoConfigurationImportFilters();
			for (AutoConfigurationImportFilter filter : filters) {
				invokeAwareMethods(filter);
			}
			this.configurationClassFilter = new ConfigurationClassFilter(this.beanClassLoader, filters);
		}
		return this.configurationClassFilter;
	}

	protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
		return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
	}

这里就是通过SpringFactoriesLoader获取AutoConfigurationImportFilter实例,然后封装成ConfigurationClassFilter对象

spring.factories里配置了什么?其实就是配置了3个Condition,OnBeanCondition、OnClassCondition、OnWebApplicationCondition。也可以自行扩展

# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

ConfigurationClassFilter是什么?其实就是把配置的AutoConfigurationImportFilter存了一下

	private static class ConfigurationClassFilter {
		private final AutoConfigurationMetadata autoConfigurationMetadata;
		private final List<AutoConfigurationImportFilter> filters;
    }

2、AutoConfigurationImportSelector.ConfigurationClassFilter#filter过滤掉不满足Condition过滤掉

		List<String> filter(List<String> configurations) {
			long startTime = System.nanoTime();
			String[] candidates = StringUtils.toStringArray(configurations);
			boolean skipped = false;
			for (AutoConfigurationImportFilter filter : this.filters) {
				boolean[] match = filter.match(candidates, this.autoConfigurationMetadata);
				for (int i = 0; i < match.length; i++) {
					if (!match[i]) {
						candidates[i] = null;
						skipped = true;
					}
				}
			}
			if (!skipped) {
				return configurations;
			}
			List<String> result = new ArrayList<>(candidates.length);
			for (String candidate : candidates) {
				if (candidate != null) {
					result.add(candidate);
				}
			}
			if (logger.isTraceEnabled()) {
				int numberFiltered = configurations.size() - result.size();
				logger.trace("Filtered " + numberFiltered + " auto configuration class in "
						+ TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
			}
			return result;
		}

主要是第一个for循环,调用所有的filter,把不满足condition的配置类都过滤掉

用法&例子

@Conditional

就是一个注解,可以指定一组Condition,还需要其他地方获取这些Condition才能生效,例如前面的ConditionEvaluator和AutoConfigurationImportSelector

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

	Class<? extends Condition>[] value();
}

@Conditional也是一个元注解,能够用在其他注解上,利用spring的注解机制也能够获取到Condition,例如@ConditionalOnBean、@ConditionalOnClass,也能够容易的扩展自己的注解

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

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

OnBeanCondition

OnBeanCondition是一个Condition实现,类定义如下

class OnBeanCondition extends FilteringSpringBootCondition implements ConfigurationCondition {
}

结合前面介绍的FilteringSpringBootCondition抽象类和ConfigurationCondition接口,OnBeanCondition是可以有两种用法的:
1、作为ConfigurationCondition的实现,在ConditionEvaluator类中使用,主要是下面几个注解

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

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

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

2、是AutoConfigurationImportFilter的实现,在AutoConfigurationImportSelector类中过滤掉一部分配置类

分别来看

作为ConfigurationCondition

@Order(Ordered.LOWEST_PRECEDENCE)
class OnBeanCondition extends FilteringSpringBootCondition implements ConfigurationCondition {

	@Override
	public ConfigurationPhase getConfigurationPhase() {
		return ConfigurationPhase.REGISTER_BEAN;
	}

	@Override
	public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
		ConditionMessage matchMessage = ConditionMessage.empty();
		MergedAnnotations annotations = metadata.getAnnotations();
		if (annotations.isPresent(ConditionalOnBean.class)) {
			Spec<ConditionalOnBean> spec = new Spec<>(context, metadata, annotations, ConditionalOnBean.class);
			MatchResult matchResult = getMatchingBeans(context, spec);
			if (!matchResult.isAllMatched()) {
				String reason = createOnBeanNoMatchReason(matchResult);
				return ConditionOutcome.noMatch(spec.message().because(reason));
			}
			matchMessage = spec.message(matchMessage).found("bean", "beans").items(Style.QUOTE,
					matchResult.getNamesOfAllMatches());
		}
		if (metadata.isAnnotated(ConditionalOnSingleCandidate.class.getName())) {
			Spec<ConditionalOnSingleCandidate> spec = new SingleCandidateSpec(context, metadata, annotations);
			MatchResult matchResult = getMatchingBeans(context, spec);
			if (!matchResult.isAllMatched()) {
				return ConditionOutcome.noMatch(spec.message().didNotFind("any beans").atAll());
			}
			else if (!hasSingleAutowireCandidate(context.getBeanFactory(), matchResult.getNamesOfAllMatches(),
					spec.getStrategy() == SearchStrategy.ALL)) {
				return ConditionOutcome.noMatch(spec.message().didNotFind("a primary bean from beans")
						.items(Style.QUOTE, matchResult.getNamesOfAllMatches()));
			}
			matchMessage = spec.message(matchMessage).found("a primary bean from beans").items(Style.QUOTE,
					matchResult.getNamesOfAllMatches());
		}
		if (metadata.isAnnotated(ConditionalOnMissingBean.class.getName())) {
			Spec<ConditionalOnMissingBean> spec = new Spec<>(context, metadata, annotations,
					ConditionalOnMissingBean.class);
			MatchResult matchResult = getMatchingBeans(context, spec);
			if (matchResult.isAnyMatched()) {
				String reason = createOnMissingBeanNoMatchReason(matchResult);
				return ConditionOutcome.noMatch(spec.message().because(reason));
			}
			matchMessage = spec.message(matchMessage).didNotFind("any beans").atAll();
		}
		return ConditionOutcome.match(matchMessage);
	}
}

1、标注了@Order注解,会在ConditionEvaluator类中和其他条件一起排序
2、实现了getConfigurationPhase方法,该方法返回的是REGISTER_BEAN,意味着bean注册时该条件才会起作用。如果在配置类上使用该注解,解析配置类时该条件会被忽略
3、实现了getMatchOutcome方法,这个方法里处理@ConditionalOnBean、@ConditionalOnSingleCandidate、@ConditionalOnMissingBean三个注解

作为AutoConfigurationImportFilter

class OnBeanCondition extends FilteringSpringBootCondition implements ConfigurationCondition {

	@Override
	protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
			AutoConfigurationMetadata autoConfigurationMetadata) {
		ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
		for (int i = 0; i < outcomes.length; i++) {
			String autoConfigurationClass = autoConfigurationClasses[i];
			if (autoConfigurationClass != null) {
				Set<String> onBeanTypes = autoConfigurationMetadata.getSet(autoConfigurationClass, "ConditionalOnBean");
				outcomes[i] = getOutcome(onBeanTypes, ConditionalOnBean.class);
				if (outcomes[i] == null) {
					Set<String> onSingleCandidateTypes = autoConfigurationMetadata.getSet(autoConfigurationClass,
							"ConditionalOnSingleCandidate");
					outcomes[i] = getOutcome(onSingleCandidateTypes, ConditionalOnSingleCandidate.class);
				}
			}
		}
		return outcomes;
	}

	private ConditionOutcome getOutcome(Set<String> requiredBeanTypes, Class<? extends Annotation> annotation) {
		List<String> missing = filter(requiredBeanTypes, ClassNameFilter.MISSING, getBeanClassLoader());
		if (!missing.isEmpty()) {
			ConditionMessage message = ConditionMessage.forCondition(annotation)
					.didNotFind("required type", "required types").items(Style.QUOTE, missing);
			return ConditionOutcome.noMatch(message);
		}
		return null;
	}
}

作为AutoConfigurationImportFilter时,仅处理@ConditionalOnBean和@ConditionalOnSingleCandidate。getOutcomes通过for循环调用getOutcome处理每一个autoConfigurationClass,getOutcome调用的filter方法看requiredBeanTypes里面哪些bean beanFacotry不存在,如果有不存在的,返回noMatch;如果没有不存在的,返回null表示当前match,还需要继续看其他Condition

OnClassCondition

@Order(Ordered.HIGHEST_PRECEDENCE)
class OnClassCondition extends FilteringSpringBootCondition {
}

OnClassCondition实现了FilteringSpringBootCondition,和OnBeanCondition类似,也会有两个作用。但OnClassCondition没有实现ConfigurationCondition,所以在PARSE_CONFIGURATION、REGISTER_BEAN阶段都会起作用

看一下作为Condition的实现
OnClassCondition会处理@ConditionalOnClass和@ConditionalOnMissingClass两个注解,首先都会通过getCandidates获取注解上标注的类名,然后处理ConditionalOnClass时,通过filter获取标注了的但不存在的类,如果不为空则条件不满足;处理ConditionalOnMissingClass时,通过filter获取标注了的但存在的类,如果不为空则条件不满足

	public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
		ClassLoader classLoader = context.getClassLoader();
		ConditionMessage matchMessage = ConditionMessage.empty();
		List<String> onClasses = getCandidates(metadata, ConditionalOnClass.class);
		if (onClasses != null) {
			List<String> missing = filter(onClasses, ClassNameFilter.MISSING, classLoader);
			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<String> onMissingClasses = getCandidates(metadata, ConditionalOnMissingClass.class);
		if (onMissingClasses != null) {
			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);
	}

OnExpressionCondition

@Order(Ordered.LOWEST_PRECEDENCE - 20)
class OnExpressionCondition extends SpringBootCondition {

	@Override
	public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
		String expression = (String) metadata.getAnnotationAttributes(ConditionalOnExpression.class.getName())
				.get("value");
		expression = wrapIfNecessary(expression);
		ConditionMessage.Builder messageBuilder = ConditionMessage.forCondition(ConditionalOnExpression.class,
				"(" + expression + ")");
		expression = context.getEnvironment().resolvePlaceholders(expression);
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		if (beanFactory != null) {
			boolean result = evaluateExpression(beanFactory, expression);
			return new ConditionOutcome(result, messageBuilder.resultedIn(result));
		}
		return ConditionOutcome.noMatch(messageBuilder.because("no BeanFactory available."));
	}

	private Boolean evaluateExpression(ConfigurableListableBeanFactory beanFactory, String expression) {
		BeanExpressionResolver resolver = beanFactory.getBeanExpressionResolver();
		if (resolver == null) {
			resolver = new StandardBeanExpressionResolver();
		}
		BeanExpressionContext expressionContext = new BeanExpressionContext(beanFactory, null);
		Object result = resolver.evaluate(expression, expressionContext);
		return (result != null && (boolean) result);
	}

	private String wrapIfNecessary(String expression) {
		if (!expression.startsWith("#{")) {
			return "#{" + expression + "}";
		}
		return expression;
	}

}

OnExpressionCondition只继承了SpringBootCondition,所以只有一种用法。实现上首先通过context.getEnvironment().resolvePlaceholders(expression)替换了表达式里的${}变量,然后通过BeanExpressionResolver(默认是StandardBeanExpressionResolver,即SPEL表达式)去解析表达式的值,即true/false

OnPropertyCondition

value和name是一个,prefix+name指定属性名,havingValue指定属性的值,matchIfMissing为true表示属性不存在时条件成立
具体的havingValue的行为

Property ValuehavingValue=""havingValue=“true”havingValue=“false”havingValue=“foo”
“true”yesyesnono
“false”nonoyesno
“foo”yesnonoyes
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnPropertyCondition.class)
public @interface ConditionalOnProperty {

	String[] value() default {};

	String prefix() default "";

	String[] name() default {};

	String havingValue() default "";

	boolean matchIfMissing() default false;
}

OnPropertyCondition继承了SpringBootCondition,然后实现getMatchOutcome方法

举报

相关推荐

0 条评论