Make @Configuration class enhancement idempotent
The registration of more than one ConfigurationClassPostProcessor results in the double-enhancement of @Configuration classes, i.e. a two-deep CGLIB subclass hierarchy is created. As a side-effect of changes introduced in 3.1 M2 fixing SPR-8080, this behavior now results in an infinite loop at CGLIB callback processing time, leading to a StackOverflowException which is then suppressed by the container, and ultimately results in the user being presented with an unintuitive "Bean 'x' is not already in creation" exception. This fix introduces a marker interface 'EnhancedConfiguration' to be implemented by all generated @Configuration subclasses. The configuration class enhancer can then behave in an idempotent fashion by checking to see whether a candidate @Configuration class is already assignable to this type i.e. already enhanced and ignore it if so. Naturally, users should avoid registering more than one ConfigurationClassPostProcessor, but this is not always possible. As with the case in point, SPR-8824 originates from problems with spring-data-neo4j, which explicitly registers its own ConfigurationClassPostProcessor. The user has little control over this arrangement, so it is important that the framework is defensive as described above. Issue: SPR-8824
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:neo4j="http://www.springframework.org/schema/data/neo4j"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/data/neo4j http://www.springframework.org/schema/data/neo4j/spring-neo4j-2.0.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
|
||||
|
||||
<bean id="a" class="org.springframework.context.annotation.ConfigurationClassPostProcessor"/>
|
||||
<bean id="b" class="org.springframework.context.annotation.ConfigurationClassPostProcessor"/>
|
||||
<bean id="c" class="org.springframework.context.annotation.DuplicateConfigurationClassPostProcessorTests$Config"/>
|
||||
</beans>
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.springframework.context.annotation.configuration;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
|
||||
/**
|
||||
* Corners the bug originally reported by SPR-8824, where the presence of two
|
||||
* {@link ConfigurationClassPostProcessor} beans in combination with a @Configuration
|
||||
* class having at least one @Bean method causes a "Singleton 'foo' isn't currently in
|
||||
* creation" exception.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1
|
||||
*/
|
||||
public class DuplicateConfigurationClassPostProcessorTests {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
GenericApplicationContext ctx = new GenericApplicationContext();
|
||||
ctx.registerBeanDefinition("a", new RootBeanDefinition(ConfigurationClassPostProcessor.class));
|
||||
ctx.registerBeanDefinition("b", new RootBeanDefinition(ConfigurationClassPostProcessor.class));
|
||||
ctx.registerBeanDefinition("myConfig", new RootBeanDefinition(Config.class));
|
||||
ctx.refresh();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
@Bean
|
||||
public String string() {
|
||||
return "bean";
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user