From c25cbe5522a13eee1fd649fe45e94f3dbeae1f09 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 10 Sep 2012 22:12:54 +0200 Subject: [PATCH] @Import'ed configuration classes get properly registered in case of same class name (second try) Issue: SPR-9243 --- .../AnnotatedBeanDefinitionReader.java | 14 ++--- .../AnnotationBeanNameGenerator.java | 14 +---- ...onfigurationClassBeanDefinitionReader.java | 23 +++----- .../annotation/ConfigurationClassParser.java | 7 +-- .../ConfigurationClassPostProcessor.java | 56 +++++++++++++------ 5 files changed, 59 insertions(+), 55 deletions(-) diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java index 82cea7c49c..cfbc423714 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java @@ -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 { *

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... 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 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)); } } diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationBeanNameGenerator.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationBeanNameGenerator.java index 515aa2e717..60a05635aa 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationBeanNameGenerator.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationBeanNameGenerator.java @@ -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. - *

The default implementation delegates to {@link #buildDefaultBeanName(BeanDefinition)}, - * appending a counter suffix if necessary to make the bean name unique in the given registry. + *

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 null) */ 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); } /** diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java index 02b4125e61..e7fa93a246 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java @@ -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()) { diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java index b5754eba79..3f92029066 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java @@ -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); } diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java index 9736099c6f..376bff788a 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java @@ -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). *

Note that this strategy does not apply to {@link Bean} methods. *

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 * } 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 {