@Import'ed configuration classes get properly registered in case of same class name (second try)
Issue: SPR-9243
This commit is contained in:
@@ -52,6 +52,7 @@ public class AnnotatedBeanDefinitionReader {
|
||||
|
||||
private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code AnnotatedBeanDefinitionReader} for the given registry.
|
||||
* If the registry is {@link EnvironmentCapable}, e.g. is an {@code ApplicationContext},
|
||||
@@ -78,10 +79,8 @@ public class AnnotatedBeanDefinitionReader {
|
||||
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
|
||||
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
|
||||
Assert.notNull(environment, "Environment must not be null");
|
||||
|
||||
this.registry = registry;
|
||||
this.environment = environment;
|
||||
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
|
||||
}
|
||||
|
||||
@@ -115,8 +114,8 @@ public class AnnotatedBeanDefinitionReader {
|
||||
* <p>The default is an {@link AnnotationScopeMetadataResolver}.
|
||||
*/
|
||||
public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
|
||||
this.scopeMetadataResolver = (scopeMetadataResolver != null ? scopeMetadataResolver
|
||||
: new AnnotationScopeMetadataResolver());
|
||||
this.scopeMetadataResolver =
|
||||
(scopeMetadataResolver != null ? scopeMetadataResolver : new AnnotationScopeMetadataResolver());
|
||||
}
|
||||
|
||||
public void register(Class<?>... annotatedClasses) {
|
||||
@@ -136,7 +135,6 @@ public class AnnotatedBeanDefinitionReader {
|
||||
public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
|
||||
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
|
||||
AnnotationMetadata metadata = abd.getMetadata();
|
||||
|
||||
if (metadata.isAnnotated(Profile.class.getName())) {
|
||||
AnnotationAttributes profile = MetadataUtils.attributesFor(metadata, Profile.class);
|
||||
if (!this.environment.acceptsProfiles(profile.getStringArray("value"))) {
|
||||
@@ -151,9 +149,11 @@ public class AnnotatedBeanDefinitionReader {
|
||||
for (Class<? extends Annotation> qualifier : qualifiers) {
|
||||
if (Primary.class.equals(qualifier)) {
|
||||
abd.setPrimary(true);
|
||||
} else if (Lazy.class.equals(qualifier)) {
|
||||
}
|
||||
else if (Lazy.class.equals(qualifier)) {
|
||||
abd.setLazyInit(true);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import java.beans.Introspector;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
@@ -122,22 +121,13 @@ public class AnnotationBeanNameGenerator implements BeanNameGenerator {
|
||||
|
||||
/**
|
||||
* Derive a default bean name from the given bean definition.
|
||||
* <p>The default implementation delegates to {@link #buildDefaultBeanName(BeanDefinition)},
|
||||
* appending a counter suffix if necessary to make the bean name unique in the given registry.
|
||||
* <p>The default implementation delegates to {@link #buildDefaultBeanName(BeanDefinition)}.
|
||||
* @param definition the bean definition to build a bean name for
|
||||
* @param registry the registry that the given bean definition is being registered with
|
||||
* @return the default bean name (never <code>null</code>)
|
||||
*/
|
||||
protected String buildDefaultBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
|
||||
String generatedName = buildDefaultBeanName(definition);
|
||||
// Increase counter until the id is unique.
|
||||
String id = generatedName;
|
||||
int counter = 0;
|
||||
while (registry.containsBeanDefinition(id)) {
|
||||
counter++;
|
||||
id = generatedName + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR + counter;
|
||||
}
|
||||
return id;
|
||||
return buildDefaultBeanName(definition);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,7 +49,6 @@ import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.MethodMetadata;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.springframework.context.annotation.MetadataUtils.*;
|
||||
@@ -83,29 +82,25 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
|
||||
private final Environment environment;
|
||||
|
||||
private final BeanNameGenerator beanNameGenerator;
|
||||
private final BeanNameGenerator importBeanNameGenerator;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@link ConfigurationClassBeanDefinitionReader} instance that will be used
|
||||
* to populate the given {@link BeanDefinitionRegistry}.
|
||||
* @param problemReporter
|
||||
* @param metadataReaderFactory
|
||||
*/
|
||||
public ConfigurationClassBeanDefinitionReader(
|
||||
BeanDefinitionRegistry registry, SourceExtractor sourceExtractor,
|
||||
ProblemReporter problemReporter, MetadataReaderFactory metadataReaderFactory,
|
||||
ResourceLoader resourceLoader, Environment environment,
|
||||
BeanNameGenerator beanNameGenerator) {
|
||||
ResourceLoader resourceLoader, Environment environment, BeanNameGenerator importBeanNameGenerator) {
|
||||
|
||||
Assert.notNull(beanNameGenerator, "BeanNameGenerator must not be null");
|
||||
this.registry = registry;
|
||||
this.sourceExtractor = sourceExtractor;
|
||||
this.problemReporter = problemReporter;
|
||||
this.metadataReaderFactory = metadataReaderFactory;
|
||||
this.resourceLoader = resourceLoader;
|
||||
this.environment = environment;
|
||||
this.beanNameGenerator = beanNameGenerator;
|
||||
this.importBeanNameGenerator = importBeanNameGenerator;
|
||||
}
|
||||
|
||||
|
||||
@@ -124,7 +119,9 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
* class itself, all its {@link Bean} methods
|
||||
*/
|
||||
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass) {
|
||||
doLoadBeanDefinitionForConfigurationClassIfNecessary(configClass);
|
||||
if (configClass.isImported()) {
|
||||
registerBeanDefinitionForImportedConfigurationClass(configClass);
|
||||
}
|
||||
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
|
||||
loadBeanDefinitionsForBeanMethod(beanMethod);
|
||||
}
|
||||
@@ -134,17 +131,13 @@ class ConfigurationClassBeanDefinitionReader {
|
||||
/**
|
||||
* Register the {@link Configuration} class itself as a bean definition.
|
||||
*/
|
||||
private void doLoadBeanDefinitionForConfigurationClassIfNecessary(ConfigurationClass configClass) {
|
||||
if (!configClass.isImported()) {
|
||||
return;
|
||||
}
|
||||
|
||||
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
|
||||
AnnotationMetadata metadata = configClass.getMetadata();
|
||||
BeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
|
||||
String className = metadata.getClassName();
|
||||
configBeanDef.setBeanClassName(className);
|
||||
if (ConfigurationClassUtils.checkConfigurationClassCandidate(configBeanDef, this.metadataReaderFactory)) {
|
||||
String configBeanName = this.beanNameGenerator.generateBeanName(configBeanDef, this.registry);
|
||||
String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
|
||||
this.registry.registerBeanDefinition(configBeanName, configBeanDef);
|
||||
configClass.setBeanName(configBeanName);
|
||||
if (logger.isDebugEnabled()) {
|
||||
|
||||
@@ -101,9 +101,8 @@ class ConfigurationClassParser {
|
||||
* to populate the set of configuration classes.
|
||||
*/
|
||||
public ConfigurationClassParser(MetadataReaderFactory metadataReaderFactory,
|
||||
ProblemReporter problemReporter, Environment environment,
|
||||
ResourceLoader resourceLoader, BeanNameGenerator beanNameGenerator,
|
||||
BeanDefinitionRegistry registry) {
|
||||
ProblemReporter problemReporter, Environment environment, ResourceLoader resourceLoader,
|
||||
BeanNameGenerator componentScanBeanNameGenerator, BeanDefinitionRegistry registry) {
|
||||
|
||||
this.metadataReaderFactory = metadataReaderFactory;
|
||||
this.problemReporter = problemReporter;
|
||||
@@ -111,7 +110,7 @@ class ConfigurationClassParser {
|
||||
this.resourceLoader = resourceLoader;
|
||||
this.registry = registry;
|
||||
this.componentScanParser = new ComponentScanAnnotationParser(
|
||||
resourceLoader, environment, beanNameGenerator, registry);
|
||||
resourceLoader, environment, componentScanBeanNameGenerator, registry);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -43,7 +43,6 @@ import org.springframework.beans.factory.parsing.PassThroughSourceExtractor;
|
||||
import org.springframework.beans.factory.parsing.ProblemReporter;
|
||||
import org.springframework.beans.factory.parsing.SourceExtractor;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
@@ -92,6 +91,12 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
private static final boolean cglibAvailable = ClassUtils.isPresent(
|
||||
"net.sf.cglib.proxy.Enhancer", ConfigurationClassPostProcessor.class.getClassLoader());
|
||||
|
||||
private static final String IMPORT_AWARE_PROCESSOR_BEAN_NAME =
|
||||
ConfigurationClassPostProcessor.class.getName() + ".importAwareProcessor";
|
||||
|
||||
private static final String IMPORT_REGISTRY_BEAN_NAME =
|
||||
ConfigurationClassPostProcessor.class.getName() + ".importRegistry";
|
||||
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
@@ -115,7 +120,18 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
|
||||
private ConfigurationClassBeanDefinitionReader reader;
|
||||
|
||||
private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
|
||||
private boolean localBeanNameGeneratorSet = false;
|
||||
|
||||
/* using short class names as default bean names */
|
||||
private BeanNameGenerator componentScanBeanNameGenerator = new AnnotationBeanNameGenerator();
|
||||
|
||||
/* using fully qualified class names as default bean names */
|
||||
private BeanNameGenerator importBeanNameGenerator = new AnnotationBeanNameGenerator() {
|
||||
@Override
|
||||
protected String buildDefaultBeanName(BeanDefinition definition) {
|
||||
return definition.getBeanClassName();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
@@ -148,23 +164,27 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link BeanNameGenerator} to be used when registering imported and nested
|
||||
* {@link Configuration} classes. The default is {@link AnnotationBeanNameGenerator}.
|
||||
* Set the {@link BeanNameGenerator} to be used when triggering component scanning
|
||||
* from {@link Configuration} classes and when registering {@link Import}'ed
|
||||
* configuration classes. The default is a standard {@link AnnotationBeanNameGenerator}
|
||||
* for scanned components (compatible with the default in {@link ClassPathBeanDefinitionScanner})
|
||||
* and a variant thereof for imported configuration classes (using unique fully-qualified
|
||||
* class names instead of standard component overriding).
|
||||
* <p>Note that this strategy does <em>not</em> apply to {@link Bean} methods.
|
||||
* <p>This setter is typically only appropriate when configuring the post-processor as
|
||||
* a standalone bean definition in XML, e.g. not using the dedicated
|
||||
* {@code AnnotationConfig*} application contexts or the {@code
|
||||
* <context:annotation-config>} element. Any bean name generator specified against
|
||||
* the application context will take precedence over any value set here.
|
||||
* @param beanNameGenerator the strategy to use when generating configuration class
|
||||
* bean names
|
||||
* @since 3.1.1
|
||||
* @see AnnotationConfigApplicationContext#setBeanNameGenerator(BeanNameGenerator)
|
||||
* @see AnnotationConfigUtils#CONFIGURATION_BEAN_NAME_GENERATOR
|
||||
*/
|
||||
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
|
||||
Assert.notNull(beanNameGenerator, "BeanNameGenerator must not be null");
|
||||
this.beanNameGenerator = beanNameGenerator;
|
||||
this.localBeanNameGeneratorSet = true;
|
||||
this.componentScanBeanNameGenerator = beanNameGenerator;
|
||||
this.importBeanNameGenerator = beanNameGenerator;
|
||||
}
|
||||
|
||||
public void setEnvironment(Environment environment) {
|
||||
@@ -189,7 +209,8 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
* Derive further bean definitions from the configuration classes in the registry.
|
||||
*/
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
|
||||
BeanDefinitionReaderUtils.registerWithGeneratedName(new RootBeanDefinition(ImportAwareBeanPostProcessor.class), registry);
|
||||
registry.registerBeanDefinition(IMPORT_AWARE_PROCESSOR_BEAN_NAME,
|
||||
new RootBeanDefinition(ImportAwareBeanPostProcessor.class));
|
||||
int registryId = System.identityHashCode(registry);
|
||||
if (this.registriesPostProcessed.contains(registryId)) {
|
||||
throw new IllegalStateException(
|
||||
@@ -244,15 +265,17 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
SingletonBeanRegistry singletonRegistry = null;
|
||||
if (registry instanceof SingletonBeanRegistry) {
|
||||
singletonRegistry = (SingletonBeanRegistry) registry;
|
||||
if (singletonRegistry.containsSingleton(CONFIGURATION_BEAN_NAME_GENERATOR)) {
|
||||
this.beanNameGenerator = (BeanNameGenerator) singletonRegistry.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
|
||||
if (!this.localBeanNameGeneratorSet && singletonRegistry.containsSingleton(CONFIGURATION_BEAN_NAME_GENERATOR)) {
|
||||
BeanNameGenerator generator = (BeanNameGenerator) singletonRegistry.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
|
||||
this.componentScanBeanNameGenerator = generator;
|
||||
this.importBeanNameGenerator = generator;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse each @Configuration class
|
||||
ConfigurationClassParser parser = new ConfigurationClassParser(
|
||||
this.metadataReaderFactory, this.problemReporter, this.environment,
|
||||
this.resourceLoader, this.beanNameGenerator, registry);
|
||||
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
|
||||
for (BeanDefinitionHolder holder : configCandidates) {
|
||||
BeanDefinition bd = holder.getBeanDefinition();
|
||||
try {
|
||||
@@ -287,16 +310,15 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
// Read the model and create bean definitions based on its content
|
||||
if (this.reader == null) {
|
||||
this.reader = new ConfigurationClassBeanDefinitionReader(
|
||||
registry, this.sourceExtractor, this.problemReporter,
|
||||
this.metadataReaderFactory, this.resourceLoader, this.environment,
|
||||
this.beanNameGenerator);
|
||||
registry, this.sourceExtractor, this.problemReporter, this.metadataReaderFactory,
|
||||
this.resourceLoader, this.environment, this.importBeanNameGenerator);
|
||||
}
|
||||
this.reader.loadBeanDefinitions(parser.getConfigurationClasses());
|
||||
|
||||
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
|
||||
if (singletonRegistry != null) {
|
||||
if (!singletonRegistry.containsSingleton("importRegistry")) {
|
||||
singletonRegistry.registerSingleton("importRegistry", parser.getImportRegistry());
|
||||
if (!singletonRegistry.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
|
||||
singletonRegistry.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -359,7 +381,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (bean instanceof ImportAware) {
|
||||
ImportRegistry importRegistry = beanFactory.getBean(ImportRegistry.class);
|
||||
ImportRegistry importRegistry = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class);
|
||||
String importingClass = importRegistry.getImportingClassFor(bean.getClass().getSuperclass().getName());
|
||||
if (importingClass != null) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user