Spring @Conditional注解从源码层讲解
xuguofeng2016 人气:0本文通过阅读@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中封装了目标组件的注解元信息,可以通过他获取到目标组件的注解相关信息,比如是否被某个注解标注、某个注解的属性等。
metadata.isAnnotated(Conditional.class.getName())
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); } } } }
加载全部内容