A BeanDefinitionRegistryPostProcessor may register other BeanDefinitionRegistryPostProcessors

We're using the same subtle PriorityOrdered/Ordered/non-ordered separation as for regular BeanFactoryPostProcessors and BeanPostProcessors now. Additionally, we're re-detecting BeanDefinitionRegistryPostProcessor bean names after every invocation phase, up until no further ones appear.

Issue: SPR-10630
This commit is contained in:
Juergen Hoeller
2013-08-28 12:49:53 +02:00
parent bb18f81b50
commit bb971cecf1
5 changed files with 447 additions and 356 deletions

View File

@@ -21,15 +21,12 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.stereotype.Component;
@@ -38,25 +35,19 @@ import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
/**
* Tests for {@link Conditional} beans.
* Test for {@link Conditional} beans.
*
* @author Phillip Webb
*/
@SuppressWarnings("resource")
public class ConfigurationClassWithConditionTests {
private final AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
@Rule
public ExpectedException thrown = ExpectedException.none();
@After
public void closeContext() {
ctx.close();
}
@Test
public void conditionalOnMissingBeanMatch() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(BeanOneConfiguration.class, BeanTwoConfiguration.class);
ctx.refresh();
assertTrue(ctx.containsBean("bean1"));
@@ -66,6 +57,7 @@ public class ConfigurationClassWithConditionTests {
@Test
public void conditionalOnMissingBeanNoMatch() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(BeanTwoConfiguration.class);
ctx.refresh();
assertFalse(ctx.containsBean("bean1"));
@@ -75,6 +67,7 @@ public class ConfigurationClassWithConditionTests {
@Test
public void conditionalOnBeanMatch() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(BeanOneConfiguration.class, BeanThreeConfiguration.class);
ctx.refresh();
assertTrue(ctx.containsBean("bean1"));
@@ -83,6 +76,7 @@ public class ConfigurationClassWithConditionTests {
@Test
public void conditionalOnBeanNoMatch() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(BeanThreeConfiguration.class);
ctx.refresh();
assertFalse(ctx.containsBean("bean1"));
@@ -91,6 +85,7 @@ public class ConfigurationClassWithConditionTests {
@Test
public void metaConditional() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(ConfigurationWithMetaCondition.class);
ctx.refresh();
assertTrue(ctx.containsBean("bean"));
@@ -98,6 +93,7 @@ public class ConfigurationClassWithConditionTests {
@Test
public void nonConfigurationClass() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(NonConfigurationClass.class);
ctx.refresh();
thrown.expect(NoSuchBeanDefinitionException.class);
@@ -106,6 +102,7 @@ public class ConfigurationClassWithConditionTests {
@Test
public void methodConditional() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(ConditionOnMethodConfiguration.class);
ctx.refresh();
thrown.expect(NoSuchBeanDefinitionException.class);
@@ -119,25 +116,6 @@ public class ConfigurationClassWithConditionTests {
ctx.refresh();
}
@Test
public void importsNotLoaded() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(ImportsNotLoaded.class);
ctx.refresh();
assertThat(ctx.containsBeanDefinition("a"), equalTo(false));
assertThat(ctx.containsBeanDefinition("b"), equalTo(false));
}
@Test
public void sensibleConditionContext() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.setResourceLoader(new DefaultResourceLoader());
ctx.setClassLoader(getClass().getClassLoader());
ctx.register(SensibleConditionContext.class);
ctx.refresh();
assertThat(ctx.getBean(ExampleBean.class), instanceOf(ExampleBean.class));
}
@Configuration
static class BeanOneConfiguration {
@Bean
@@ -279,70 +257,6 @@ public class ConfigurationClassWithConditionTests {
}
@Configuration
@Never
@Import({ ConfigurationNotLoaded.class, RegistrarNotLoaded.class, ImportSelectorNotLoaded.class })
static class ImportsNotLoaded {
static {
if (true) throw new RuntimeException();
}
}
@Configuration
static class ConfigurationNotLoaded {
@Bean
public String a() {
return "a";
}
}
static class RegistrarNotLoaded implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
throw new RuntimeException();
}
}
static class ImportSelectorNotLoaded implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] { SelectedConfigurationNotLoaded.class.getName() };
}
}
@Configuration
static class SelectedConfigurationNotLoaded {
@Bean
public String b() {
return "b";
}
}
@Configuration
@Conditional(SensibleConditionContextCondition.class)
static class SensibleConditionContext {
@Bean
ExampleBean exampleBean() {
return new ExampleBean();
}
}
static class SensibleConditionContextCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
assertThat(context.getBeanFactory(), notNullValue());
assertThat(context.getClassLoader(), notNullValue());
assertThat(context.getEnvironment(), notNullValue());
assertThat(context.getRegistry(), notNullValue());
assertThat(context.getResourceLoader(), notNullValue());
return true;
}
}
static class ExampleBean {
}

View File

@@ -16,19 +16,22 @@
package org.springframework.context.support;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.tests.sample.beans.TestBean;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.core.PriorityOrdered;
import org.springframework.tests.sample.beans.TestBean;
import static org.junit.Assert.*;
/**
* Tests the interaction between {@link ApplicationContext} implementations and
@@ -93,6 +96,29 @@ public class BeanFactoryPostProcessorTests {
assertFalse(bfpp.wasCalled);
}
@Test
public void testBeanDefinitionRegistryPostProcessor() throws Exception {
StaticApplicationContext ac = new StaticApplicationContext();
ac.registerSingleton("tb1", TestBean.class);
ac.registerSingleton("tb2", TestBean.class);
TestBeanDefinitionRegistryPostProcessor bdrpp = new TestBeanDefinitionRegistryPostProcessor();
ac.addBeanFactoryPostProcessor(bdrpp);
assertFalse(bdrpp.wasCalled);
ac.refresh();
assertTrue(bdrpp.wasCalled);
assertTrue(ac.getBean(TestBeanFactoryPostProcessor.class).wasCalled);
}
@Test
public void testBeanDefinitionRegistryPostProcessorRegisteringAnother() throws Exception {
StaticApplicationContext ac = new StaticApplicationContext();
ac.registerSingleton("tb1", TestBean.class);
ac.registerSingleton("tb2", TestBean.class);
ac.registerBeanDefinition("bdrpp2", new RootBeanDefinition(TestBeanDefinitionRegistryPostProcessor2.class));
ac.refresh();
assertTrue(ac.getBean(TestBeanFactoryPostProcessor.class).wasCalled);
}
public static class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@@ -110,4 +136,38 @@ public class BeanFactoryPostProcessorTests {
}
}
public static class TestBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
public boolean wasCalled;
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
registry.registerBeanDefinition("bfpp", new RootBeanDefinition(TestBeanFactoryPostProcessor.class));
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
this.wasCalled = true;
}
}
public static class TestBeanDefinitionRegistryPostProcessor2 implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
registry.registerBeanDefinition("anotherpp", new RootBeanDefinition(TestBeanDefinitionRegistryPostProcessor.class));
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
@Override
public int getOrder() {
return HIGHEST_PRECEDENCE;
}
}
}