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 982741a406c..08caf119620 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 @@ -17,6 +17,7 @@ package org.springframework.context.annotation; import java.io.IOException; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; @@ -102,9 +103,9 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo private boolean setMetadataReaderFactoryCalled = false; - private boolean postProcessBeanDefinitionRegistryCalled = false; + private final Set registriesPostProcessed = new HashSet(); - private boolean postProcessBeanFactoryCalled = false; + private final Set factoriesPostProcessed = new HashSet(); private Environment environment; @@ -163,15 +164,16 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo */ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { BeanDefinitionReaderUtils.registerWithGeneratedName(new RootBeanDefinition(ImportAwareBeanPostProcessor.class), registry); - if (this.postProcessBeanDefinitionRegistryCalled) { + int registryID = System.identityHashCode(registry); + if (this.registriesPostProcessed.contains(registryID)) { throw new IllegalStateException( - "postProcessBeanDefinitionRegistry already called for this post-processor"); + "postProcessBeanDefinitionRegistry already called for this post-processor against " + registry); } - if (this.postProcessBeanFactoryCalled) { + if (this.factoriesPostProcessed.contains(registryID)) { throw new IllegalStateException( - "postProcessBeanFactory already called for this post-processor"); + "postProcessBeanFactory already called for this post-processor against " + registry); } - this.postProcessBeanDefinitionRegistryCalled = true; + this.registriesPostProcessed.add(registryID); processConfigurationClasses(registry); } @@ -180,12 +182,13 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo * by replacing them with CGLIB-enhanced subclasses. */ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { - if (this.postProcessBeanFactoryCalled) { + int factoryID = System.identityHashCode(beanFactory); + if (this.factoriesPostProcessed.contains(factoryID)) { throw new IllegalStateException( - "postProcessBeanFactory already called for this post-processor"); + "postProcessBeanFactory already called for this post-processor against " + beanFactory); } - this.postProcessBeanFactoryCalled = true; - if (!this.postProcessBeanDefinitionRegistryCalled) { + this.factoriesPostProcessed.add(factoryID); + if (!this.registriesPostProcessed.contains(factoryID)) { // BeanDefinitionRegistryPostProcessor hook apparently not supported... // Simply call processConfigurationClasses lazily at this point then. processConfigurationClasses((BeanDefinitionRegistry)beanFactory); diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java index d3800a9d10c..d52a9db656f 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java @@ -82,6 +82,25 @@ public class ConfigurationClassPostProcessorTests { assertSame(foo, bar.foo); } + @Test + public void testProcessingAllowedOnlyOncePerProcessorRegistryPair() { + DefaultListableBeanFactory bf1 = new DefaultListableBeanFactory(); + DefaultListableBeanFactory bf2 = new DefaultListableBeanFactory(); + ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor(); + pp.postProcessBeanFactory(bf1); // first invocation -- should succeed + try { + pp.postProcessBeanFactory(bf1); // second invocation for bf1 -- should throw + fail("expected exception"); + } catch (IllegalStateException ex) { + } + pp.postProcessBeanFactory(bf2); // first invocation for bf2 -- should succeed + try { + pp.postProcessBeanFactory(bf2); // second invocation for bf2 -- should throw + fail("expected exception"); + } catch (IllegalStateException ex) { + } + } + @Configuration static class SingletonBeanConfig {