Favor local @ComponentScan annotations over meta-annotations
Work performed in conjunction with gh-30941 resulted in a regression. Specifically, prior to Spring Framework 6.1 a locally declared @ComponentScan annotation took precedence over @ComponentScan meta-annotations, which allowed "local" configuration to override "meta-present" configuration. This commit modifies the @ComponentScan search algorithm so that locally declared @ComponentScan annotations are once again favored over @ComponentScan meta-annotations (and, indirectly, composed annotations). See gh-30941 Closes gh-31704
This commit is contained in:
@@ -19,6 +19,7 @@ package org.springframework.context.annotation;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
||||
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
|
||||
@@ -32,6 +33,7 @@ import org.springframework.context.event.EventListenerMethodProcessor;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.annotation.MergedAnnotation;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -281,9 +283,10 @@ public abstract class AnnotationConfigUtils {
|
||||
}
|
||||
|
||||
static Set<AnnotationAttributes> attributesForRepeatable(AnnotationMetadata metadata,
|
||||
Class<? extends Annotation> annotationType, Class<? extends Annotation> containerType) {
|
||||
Class<? extends Annotation> annotationType, Class<? extends Annotation> containerType,
|
||||
Predicate<MergedAnnotation<? extends Annotation>> predicate) {
|
||||
|
||||
return metadata.getMergedRepeatableAnnotationAttributes(annotationType, containerType, false);
|
||||
return metadata.getMergedRepeatableAnnotationAttributes(annotationType, containerType, predicate, false, false);
|
||||
}
|
||||
|
||||
static Set<AnnotationAttributes> attributesForRepeatable(AnnotationMetadata metadata,
|
||||
|
||||
@@ -55,6 +55,7 @@ import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.MergedAnnotation;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
@@ -285,9 +286,18 @@ class ConfigurationClassParser {
|
||||
}
|
||||
}
|
||||
|
||||
// Process any @ComponentScan annotations
|
||||
// Search for locally declared @ComponentScan annotations first.
|
||||
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
|
||||
sourceClass.getMetadata(), ComponentScan.class, ComponentScans.class);
|
||||
sourceClass.getMetadata(), ComponentScan.class, ComponentScans.class,
|
||||
MergedAnnotation::isDirectlyPresent);
|
||||
|
||||
// Fall back to searching for @ComponentScan meta-annotations (which indirectly
|
||||
// includes locally declared composed annotations).
|
||||
if (componentScans.isEmpty()) {
|
||||
componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(),
|
||||
ComponentScan.class, ComponentScans.class, MergedAnnotation::isMetaPresent);
|
||||
}
|
||||
|
||||
if (!componentScans.isEmpty() &&
|
||||
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
|
||||
for (AnnotationAttributes componentScan : componentScans) {
|
||||
|
||||
Reference in New Issue
Block a user