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:
@@ -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 {
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user