本文通过阅读@Conditional注解、Condition接口、ConditionEvaluator类以及@ConditionalOnProperty(Spring Boot提供)注解源码,深入分析Spring Conditional的实现原理。
源码版本
由于不同版本的spring代码实现细节可能存在差异,此处记录一下本文使用的源码版本:
- spring 5.2.12.RELEASE
- spring-boot 2.3.8.RELEASE
@Conditional注解
标注在类或方法上,当所有指定Condition都匹配时,才允许向spring容器注册组件。
如果一个@Configuration类标注了@Conditional注解,则与该类关联的所有@Bean方法、@Import注解和@ComponentScan注解都将受指定Condition约束。
注解定义:
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Conditional {
/**
* 当所有指定Condition都匹配时,才允许向spring容器注册组件。
*
* 这个泛型的意思是接受所有Condition接口的实现类。
*/
Class<? extends Condition>[] value();
}
Condition接口
Condition接口
匹配条件。
在注册BeanDefinition之前立即检查条件,并且可以根据当时可以确定的任何条件取消组件注册。
Condition必须遵循与BeanFactoryPostProcessor相同的限制,并注意不要与bean实例交互。如果需要对与@Configuration bean交互的Condition进行更细粒度的控制,请考虑实现ConfigurationCondition接口。
接口定义:
public interface Condition {
/**
* 确定条件是否匹配。
*/
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
ConditionContext接口
用于获取BeanDefinitionRegistry、BeanFactory、Environment等。
只有一个ConditionEvaluator.ConditionContextImpl实现类(一个内部类):
class ConditionEvaluator {
private final ConditionContextImpl context;
public ConditionEvaluator(BeanDefinitionRegistry registry,
Environment environment, ResourceLoader resourceLoader) {
this.context = new ConditionContextImpl(registry, environment, resourceLoader);
}
ConditionEvaluator类
用于处理Conditional相关注解。
核心的逻辑都在这个类里面:
public boolean shouldSkip(AnnotatedTypeMetadata metadata, ConfigurationPhase phase) {
// 1. 判断目标组件是否被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);
}
// 2. 获取到所有的Condition并实例化
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. Condition排序
AnnotationAwareOrderComparator.sort(conditions);
// 4. Condition匹配验证
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;
}
核心功能4步:
- 判断目标组件是否被Conditional标注
- 获取到所有的Condition并实例化
- Condition排序
- Condition匹配验证
下文将展开说明这4个步骤。
判断目标组件是否被Conditional标注
AnnotatedTypeMetadata中封装了目标组件的注解元信息,可以通过他获取到目标组件的注解相关信息,比如是否被某个注解标注、某个注解的属性等。
AnnotatedTypeMetadata中定义了该方法的实现方式:
default boolean isAnnotated(String annotationName) {
// 通过MergedAnnotations来获取注解标注状态
return getAnnotations().isPresent(annotationName);
}
我们在之前的《Spring-@Bean注解源码分析》中介绍过,此处使用的是StandardAnnotationMetadata实现类,而该类中的MergedAnnotations是使用以下方式创建和获取的:
public StandardAnnotationMetadata(Class<?> introspectedClass, boolean nestedAnnotationsAsMap) {
super(introspectedClass);
// 这里使用的是TypeMappedAnnotations实现类
this.mergedAnnotations = MergedAnnotations.from(introspectedClass,
SearchStrategy.INHERITED_ANNOTATIONS, RepeatableContainers.none());
this.nestedAnnotationsAsMap = nestedAnnotationsAsMap;
}
@Override
public MergedAnnotations getAnnotations() {
return this.mergedAnnotations;
}
所以isAnnotated的核心判断逻辑在TypeMappedAnnotations的isPresent方法中:
public boolean isPresent(String annotationType) {
if (this.annotationFilter.matches(annotationType)) {
return false;
}
return Boolean.TRUE.equals(scan(annotationType,
IsPresent.get(this.repeatableContainers, this.annotationFilter, false)));
}
scan方法的详细逻辑还是使用java反射的Class.getDeclaredAnnotations()方法来实现的,此处不展开说明,后续会有专门的章节介绍。
获取到所有的Condition并实例化
// 2. 获取到所有的Condition并实例化
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);
}
}
// 这个方法从AnnotatedTypeMetadata中获取所有Conditional注解指定的Condition类名集
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());
}
AnnotatedTypeMetadata接口getAllAnnotationAttributes方法,这是一个default方法,用于获取指定注解的Attribute集:
default MultiValueMap<String, Object> getAllAnnotationAttributes(
String annotationName, boolean classValuesAsString) {
Adapt[] adaptations = Adapt.values(classValuesAsString, true);
return getAnnotations().stream(annotationName) // 获取到所有的注解信息
.filter(MergedAnnotationPredicates.unique(MergedAnnotation::getMetaTypes)) // 过滤
.map(MergedAnnotation::withNonMergedAttributes)
.collect(MergedAnnotationCollectors.toMultiValueMap(map ->
map.isEmpty() ? null : map, adaptations));
}
getAnnotations()返回的是TypeMappedAnnotations类型对象,他的stream方法:
public <A extends Annotation> Stream<MergedAnnotation<A>> stream(String annotationType) {
if (this.annotationFilter == AnnotationFilter.ALL) {
return Stream.empty();
}
// 这里使用java api创建Stream
return StreamSupport.stream(spliterator(annotationType), false);
}
private <A extends Annotation> Spliterator<MergedAnnotation<A>> spliterator(Object annotationType) {
return new AggregatesSpliterator<>(annotationType, getAggregates());
}
private List<Aggregate> getAggregates() {
List<Aggregate> aggregates = this.aggregates;
if (aggregates == null) {
// 这里扫描所有注解
aggregates = scan(this, new AggregatesCollector());
if (aggregates == null || aggregates.isEmpty()) {
aggregates = Collections.emptyList();
}
this.aggregates = aggregates;
}
return aggregates;
}
// 这里扫描所有注解
private <C, R> R scan(C criteria, AnnotationsProcessor<C, R> processor) {
if (this.annotations != null) {
R result = processor.doWithAnnotations(criteria, 0, this.source, this.annotations);
return processor.finish(result);
}
if (this.element != null && this.searchStrategy != null) {
return AnnotationsScanner.scan(criteria, this.element, this.searchStrategy, processor);
}
return null;
}
scan方法里面会通过递归方式使用java反射api从组件类getAnnotations以便获取到所有的注解信息,代码较多,此处不展开记录。
Condition排序
- 判断Condition类实现了PriorityOrdered接口,并使用PriorityOrdered进行排序
- 判断Condition类实现了Ordered接口,并使用Ordered进行排序
- 从Condition类获取Order注解,并使用Order注解的值进行排序
AnnotationAwareOrderComparator.sort(conditions);
public static void sort(List<?> list) {
if (list.size() > 1) {
list.sort(INSTANCE); // 这里的Comparator使用的是AnnotationAwareOrderComparator实现类
}
}
AnnotationAwareOrderComparator实现类:
public class AnnotationAwareOrderComparator extends OrderComparator {
@Override
protected Integer findOrder(Object obj) {
// 先使用父类方法获取排序,其实就是判断Ordered实现并获取排序,在本例中显然获取不到
Integer order = super.findOrder(obj);
if (order != null) {
return order;
}
// 从类标注的注解中获取排序
return findOrderFromAnnotation(obj);
}
private Integer findOrderFromAnnotation(Object obj) {
AnnotatedElement element = (obj instanceof AnnotatedElement ?
(AnnotatedElement) obj : obj.getClass());
MergedAnnotations annotations = MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY);
// 从类标注的注解中获取排序,比如Order注解,此处不展开记录了
Integer order = OrderUtils.getOrderFromAnnotations(element, annotations);
if (order == null && obj instanceof DecoratingProxy) {
return findOrderFromAnnotation(((DecoratingProxy) obj).getDecoratedClass());
}
return order;
}
@Override
public Integer getPriority(Object obj) {
if (obj instanceof Class) {
return OrderUtils.getPriority((Class<?>) obj);
}
Integer priority = OrderUtils.getPriority(obj.getClass());
if (priority == null && obj instanceof DecoratingProxy) {
return getPriority(((DecoratingProxy) obj).getDecoratedClass());
}
return priority;
}
}
public class OrderComparator implements Comparator<Object> {
@Override
public int compare(Object o1, Object o2) {
return doCompare(o1, o2, null);
}
private int doCompare(Object o1, Object o2, OrderSourceProvider sourceProvider) {
// 优先级排序判断
boolean p1 = (o1 instanceof PriorityOrdered);
boolean p2 = (o2 instanceof PriorityOrdered);
if (p1 && !p2) {
return -1;
} else if (p2 && !p1) {
return 1;
}
// 分别获取到order并比较
int i1 = getOrder(o1, sourceProvider);
int i2 = getOrder(o2, sourceProvider);
return Integer.compare(i1, i2);
}
private int getOrder(Object obj, OrderSourceProvider sourceProvider) {
Integer order = null;
if (obj != null && sourceProvider != null) {
Object orderSource = sourceProvider.getOrderSource(obj);
if (orderSource != null) {
if (orderSource.getClass().isArray()) {
for (Object source : ObjectUtils.toObjectArray(orderSource)) {
order = findOrder(source);
if (order != null) {
break;
}
}
} else {
order = findOrder(orderSource);
}
}
}
// 直接执行这里
return (order != null ? order : getOrder(obj));
}
protected int getOrder(Object obj) {
if (obj != null) {
// 继续调用findOrder获取排序
// 在此处场景下调用AnnotationAwareOrderComparator的findOrder方法
Integer order = findOrder(obj);
if (order != null) {
return order;
}
}
return Ordered.LOWEST_PRECEDENCE;
}
protected Integer findOrder(Object obj) {
return (obj instanceof Ordered ? ((Ordered) obj).getOrder() : null);
}
public Integer getPriority(Object obj) {
return null;
}
}
Condition匹配验证
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;
}
}
@ConditionalOnProperty注解和OnPropertyCondition类
@ConditionalOnProperty注解
@Conditional that checks if the specified properties have a specific value. By default the properties must be present in the Environment and not equal to false. The havingValue() and matchIfMissing() attributes allow further customizations.
@Conditional(OnPropertyCondition.class)
public @interface ConditionalOnProperty {
String[] value() default {};
String prefix() default "";
String[] name() default {};
String havingValue() default "";
boolean matchIfMissing() default false;
}
OnPropertyCondition从env中检测指定env参数是否配置了指定的值,只有满足时才允许装配目标组件。
如何判断被@Conditional注解标注
前面已经介绍,spring是使用(AnnotatedTypeMetadata)metadata.isAnnotated(Conditional.class.getName())来判断组件被@Conditional注解标注的。但是@Conditional标注在@ConditionalOnProperty注解上,使用普通的(Class)clazz.isAnnotationPresent(Conditional.class)方式无法判断,那么metadata.isAnnotated方法是如何判断的呢?
从上面@ConditionalOnProperty注解定义可以知道,目标组件类标注了@ConditionalOnProperty注解,@ConditionalOnProperty注解又标注了@Conditional注解,这显然是一个递归,只有从目标组件类开始递归解析,就可以解析出目标组件类上的所有注解,以下是一个我自己编写的简单示例:
@EnableAspectJAutoProxy
@Configuration
@ComponentScan("org.net5ijy.mybatis.test.config.aop")
@ConditionalOnAop
public class ServiceAopConfig {}
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(AopCondition.class)
public @interface ConditionalOnAop {}
@Test
public void testAllResolveAnnotations() {
// 不解析以下三个注解
Set<Class<?>> exclude = new HashSet<Class<?>>() {{
add(Target.class);
add(Retention.class);
add(Documented.class);
}};
// 存放所有注解
List<Annotation> annotationList = new ArrayList<>();
// 首先获取一次组件类直接标注的注解
Annotation[] annotations = ServiceAopConfig.class.getDeclaredAnnotations();
// 递归解析
while (annotations.length > 0) {
annotationList.addAll(Arrays.asList(annotations));
// 递归解析
List<Annotation> tmp = new ArrayList<>();
for (Annotation annotation : annotations) {
Annotation[] list = annotation.annotationType().getDeclaredAnnotations();
for (Annotation a : list) {
if (!exclude.contains(a.annotationType())) {
tmp.add(a);
}
}
}
annotations = tmp.toArray(new Annotation[0]);
}
// 循环结束之后,ServiceAopConfig直接和间接标注的所有注解就都解析出来了
for (Annotation annotation : annotationList) {
System.out.println(annotation);
}
}
AnnotatedTypeMetadata接口和StandardAnnotationMetadata类
上文介绍了,spring是使用(AnnotatedTypeMetadata)metadata.isAnnotated(Conditional.class.getName())来判断组件被@Conditional注解标注的。
public interface AnnotatedTypeMetadata {
/**
* Return annotation details based on the direct annotations of the underlying element.
* @return merged annotations based on the direct annotations
* @since 5.2
*/
MergedAnnotations getAnnotations();
/**
* Determine whether the underlying element has an
* annotation or meta-annotation of the given type defined.
* @return whether a matching annotation is defined
*/
default boolean isAnnotated(String annotationName) {
return getAnnotations().isPresent(annotationName);
}
// ...
}
在我们分析的场景,此处使用的是StandardAnnotationMetadata实现类。StandardAnnotationMetadata实现类getAnnotations()返回TypeMappedAnnotations类型对象。
TypeMappedAnnotations类isPresent方法:
public boolean isPresent(String annotationType) {
if (this.annotationFilter.matches(annotationType)) {
return false;
}
// 在scan方法中
return Boolean.TRUE.equals(scan(annotationType,
IsPresent.get(this.repeatableContainers, this.annotationFilter, false)));
}
private <C, R> R scan(C criteria, AnnotationsProcessor<C, R> processor) {
if (this.annotations != null) {
R result = processor.doWithAnnotations(criteria, 0, this.source, this.annotations);
return processor.finish(result);
}
if (this.element != null && this.searchStrategy != null) {
// 执行到这里
return AnnotationsScanner.scan(criteria, this.element, this.searchStrategy, processor);
}
return null;
}
AnnotationsScanner.scan方法:
static <C, R> R scan(C context, AnnotatedElement source, SearchStrategy searchStrategy,
AnnotationsProcessor<C, R> processor) {
R result = process(context, source, searchStrategy, processor);
return processor.finish(result);
}
// 层层调用到processElement方法
private static <C, R> R processElement(C context, AnnotatedElement source,
AnnotationsProcessor<C, R> processor) {
try {
R result = processor.doWithAggregate(context, 0);
// 继续调用processor.doWithAnnotations方法
// 这里的processor是TypeMappedAnnotations.IsPresent类型对象
return (result != null ? result : processor.doWithAnnotations(
context, 0, source, getDeclaredAnnotations(source, false)));
} catch (Throwable ex) {
AnnotationUtils.handleIntrospectionFailure(source, ex);
}
return null;
}
TypeMappedAnnotations.IsPresent类doWithAnnotations方法:
public Boolean doWithAnnotations(Object requiredType, int aggregateIndex,
Object source, Annotation[] annotations) {
for (Annotation annotation : annotations) {
if (annotation != null) {
Class<? extends Annotation> type = annotation.annotationType();
if (type != null && !this.annotationFilter.matches(type)) {
if (type == requiredType || type.getName().equals(requiredType)) {
return Boolean.TRUE;
}
Annotation[] repeatedAnnotations =
this.repeatableContainers.findRepeatedAnnotations(annotation);
if (repeatedAnnotations != null) {
Boolean result = doWithAnnotations(
requiredType, aggregateIndex, source, repeatedAnnotations);
if (result != null) {
return result;
}
}
if (!this.directOnly) {
// 这里会进行递归解析
AnnotationTypeMappings mappings = AnnotationTypeMappings.forAnnotationType(type);
for (int i = 0; i < mappings.size(); i++) {
AnnotationTypeMapping mapping = mappings.get(i);
if (isMappingForType(mapping, this.annotationFilter, requiredType)) {
return Boolean.TRUE;
}
}
}
}
}
}
return null;
}
AnnotationTypeMappings.forAnnotationType方法:
static AnnotationTypeMappings forAnnotationType(Class<? extends Annotation> annotationType) {
return forAnnotationType(annotationType, AnnotationFilter.PLAIN);
}
static AnnotationTypeMappings forAnnotationType(
Class<? extends Annotation> annotationType, AnnotationFilter annotationFilter) {
return forAnnotationType(annotationType, RepeatableContainers.standardRepeatables(), annotationFilter);
}
static AnnotationTypeMappings forAnnotationType(Class<? extends Annotation> annotationType,
RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter) {
return new AnnotationTypeMappings(repeatableContainers, annotationFilter, annotationType);
}
AnnotationTypeMappings对象:
private AnnotationTypeMappings(RepeatableContainers repeatableContainers,
AnnotationFilter filter, Class<? extends Annotation> annotationType) {
this.repeatableContainers = repeatableContainers;
this.filter = filter;
this.mappings = new ArrayList<>();
addAllMappings(annotationType);
this.mappings.forEach(AnnotationTypeMapping::afterAllMappingsSet);
}
private void addAllMappings(Class<? extends Annotation> annotationType) {
Deque<AnnotationTypeMapping> queue = new ArrayDeque<>();
addIfPossible(queue, null, annotationType, null);
// 递归解析
while (!queue.isEmpty()) {
AnnotationTypeMapping mapping = queue.removeFirst();
this.mappings.add(mapping);
addMetaAnnotationsToQueue(queue, mapping);
}
}
private void addMetaAnnotationsToQueue(Deque<AnnotationTypeMapping> queue, AnnotationTypeMapping source) {
Annotation[] metaAnnotations =
AnnotationsScanner.getDeclaredAnnotations(source.getAnnotationType(), false);
// ...
}
static Annotation[] getDeclaredAnnotations(AnnotatedElement source, boolean defensive) {
boolean cached = false;
Annotation[] annotations = declaredAnnotationCache.get(source);
if (annotations != null) {
cached = true;
} else {
// 这里使用java反射api获取类标注的注解
annotations = source.getDeclaredAnnotations();
if (annotations.length != 0) {
// ...
}
}
if (!defensive || annotations.length == 0 || !cached) {
return annotations;
}
return annotations.clone();
}
OnPropertyCondition类
class OnPropertyCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 获取所有的@ConditionalOnProperty注解属性
List<AnnotationAttributes> allAnnotationAttributes = annotationAttributesFromMultiValueMap(
metadata.getAllAnnotationAttributes(ConditionalOnProperty.class.getName()));
List<ConditionMessage> noMatch = new ArrayList<>();
List<ConditionMessage> match = new ArrayList<>();
// 遍历@ConditionalOnProperty注解属性
for (AnnotationAttributes annotationAttributes : allAnnotationAttributes) {
ConditionOutcome outcome = determineOutcome(annotationAttributes, context.getEnvironment());
(outcome.isMatch() ? match : noMatch).add(outcome.getConditionMessage());
}
if (!noMatch.isEmpty()) {
return ConditionOutcome.noMatch(ConditionMessage.of(noMatch));
}
return ConditionOutcome.match(ConditionMessage.of(match));
}
private ConditionOutcome determineOutcome(AnnotationAttributes annotationAttributes,
PropertyResolver resolver) {
Spec spec = new Spec(annotationAttributes);
List<String> missingProperties = new ArrayList<>();
List<String> nonMatchingProperties = new ArrayList<>();
// 这里在匹配env参数
// Spec类封装了prefix, havingValue, names, matchIfMissing等配置
// collectProperties方法将env参数与prefix, havingValue, names, matchIfMissing等进行匹配
spec.collectProperties(resolver, missingProperties, nonMatchingProperties);
if (!missingProperties.isEmpty()) {
return ConditionOutcome.noMatch(...);
}
if (!nonMatchingProperties.isEmpty()) {
return ConditionOutcome.noMatch(...);
}
return ConditionOutcome
.match(ConditionMessage.forCondition(ConditionalOnProperty.class, spec).because("matched"));
}
}
public abstract class SpringBootCondition implements Condition {
@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("", ex);
} catch (RuntimeException ex) {
throw new IllegalStateException("", ex);
}
}
public abstract ConditionOutcome getMatchOutcome(
ConditionContext context, AnnotatedTypeMetadata metadata);
}
(Spec)spec.collectProperties方法:
private void collectProperties(PropertyResolver resolver, List<String> missing, List<String> nonMatching) {
for (String name : this.names) {
String key = this.prefix + name;
if (resolver.containsProperty(key)) {
if (!isMatch(resolver.getProperty(key), this.havingValue)) {
nonMatching.add(name);
}
} else {
if (!this.matchIfMissing) {
missing.add(name);
}
}
}
}