Common annotation processing for imported and nested classes within configuration classes

Issue: SPR-12486
This commit is contained in:
Juergen Hoeller 2014-12-01 18:54:56 +01:00
parent c94d584f37
commit c5c5473d44
2 changed files with 173 additions and 30 deletions

View File

@ -72,6 +72,8 @@ class ConfigurationClassBeanDefinitionReader {
private static final Log logger = LogFactory.getLog(ConfigurationClassBeanDefinitionReader.class); private static final Log logger = LogFactory.getLog(ConfigurationClassBeanDefinitionReader.class);
private static final ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
private final BeanDefinitionRegistry registry; private final BeanDefinitionRegistry registry;
private final SourceExtractor sourceExtractor; private final SourceExtractor sourceExtractor;
@ -154,10 +156,16 @@ class ConfigurationClassBeanDefinitionReader {
*/ */
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) { private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
AnnotationMetadata metadata = configClass.getMetadata(); AnnotationMetadata metadata = configClass.getMetadata();
BeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata); AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(configBeanDef, this.metadataReaderFactory)) { if (ConfigurationClassUtils.checkConfigurationClassCandidate(configBeanDef, this.metadataReaderFactory)) {
ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
configBeanDef.setScope(scopeMetadata.getScopeName());
String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry); String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
this.registry.registerBeanDefinition(configBeanName, configBeanDef); AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
configClass.setBeanName(configBeanName); configClass.setBeanName(configBeanName);
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug(String.format("Registered bean definition for imported @Configuration class %s", configBeanName)); logger.debug(String.format("Registered bean definition for imported @Configuration class %s", configBeanName));

View File

@ -58,12 +58,15 @@ public class NestedConfigurationClassTests {
ctx.register(L0Config.class); ctx.register(L0Config.class);
ctx.refresh(); ctx.refresh();
assertFalse(ctx.getBeanFactory().containsSingleton("nestedConfigurationClassTests.L0Config"));
ctx.getBean(L0Config.class); ctx.getBean(L0Config.class);
ctx.getBean("l0Bean"); ctx.getBean("l0Bean");
assertTrue(ctx.getBeanFactory().containsSingleton(L0Config.L1Config.class.getName()));
ctx.getBean(L0Config.L1Config.class); ctx.getBean(L0Config.L1Config.class);
ctx.getBean("l1Bean"); ctx.getBean("l1Bean");
assertFalse(ctx.getBeanFactory().containsSingleton(L0Config.L1Config.L2Config.class.getName()));
ctx.getBean(L0Config.L1Config.L2Config.class); ctx.getBean(L0Config.L1Config.L2Config.class);
ctx.getBean("l2Bean"); ctx.getBean("l2Bean");
@ -71,14 +74,38 @@ public class NestedConfigurationClassTests {
assertThat(ctx.getBean("overrideBean", TestBean.class).getName(), is("override-l0")); assertThat(ctx.getBean("overrideBean", TestBean.class).getName(), is("override-l0"));
} }
@Test
public void twoLevelsInLiteMode() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(L0ConfigLight.class);
ctx.refresh();
assertFalse(ctx.getBeanFactory().containsSingleton("nestedConfigurationClassTests.L0ConfigLight"));
ctx.getBean(L0ConfigLight.class);
ctx.getBean("l0Bean");
assertTrue(ctx.getBeanFactory().containsSingleton(L0ConfigLight.L1ConfigLight.class.getName()));
ctx.getBean(L0ConfigLight.L1ConfigLight.class);
ctx.getBean("l1Bean");
assertFalse(ctx.getBeanFactory().containsSingleton(L0ConfigLight.L1ConfigLight.L2ConfigLight.class.getName()));
ctx.getBean(L0ConfigLight.L1ConfigLight.L2ConfigLight.class);
ctx.getBean("l2Bean");
// ensure that override order is correct
assertThat(ctx.getBean("overrideBean", TestBean.class).getName(), is("override-l0"));
}
@Test @Test
public void twoLevelsDeepWithInheritance() { public void twoLevelsDeepWithInheritance() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(S1Config.class); ctx.register(S1Config.class);
ctx.refresh(); ctx.refresh();
ctx.getBean(S1Config.class); S1Config config = ctx.getBean(S1Config.class);
ctx.getBean("l0Bean"); assertTrue(config != ctx.getBean(S1Config.class));
TestBean tb = ctx.getBean("l0Bean", TestBean.class);
assertTrue(tb == ctx.getBean("l0Bean", TestBean.class));
ctx.getBean(L0Config.L1Config.class); ctx.getBean(L0Config.L1Config.class);
ctx.getBean("l1Bean"); ctx.getBean("l1Bean");
@ -86,27 +113,71 @@ public class NestedConfigurationClassTests {
ctx.getBean(L0Config.L1Config.L2Config.class); ctx.getBean(L0Config.L1Config.L2Config.class);
ctx.getBean("l2Bean"); ctx.getBean("l2Bean");
// ensure that override order is correct // ensure that override order is correct and that it is a singleton
assertThat(ctx.getBean("overrideBean", TestBean.class).getName(), is("override-s1")); TestBean ob = ctx.getBean("overrideBean", TestBean.class);
assertThat(ob.getName(), is("override-s1"));
assertTrue(ob == ctx.getBean("overrideBean", TestBean.class));
TestBean pb1 = ctx.getBean("prototypeBean", TestBean.class);
TestBean pb2 = ctx.getBean("prototypeBean", TestBean.class);
assertTrue(pb1 != pb2);
assertTrue(pb1.getFriends().iterator().next() != pb2.getFriends().iterator().next());
} }
@Test @Test
public void twoLevelsInLiteMode() { public void twoLevelsDeepWithInheritanceThroughImport() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(L0ConfigLight.class); ctx.register(S1Importer.class);
ctx.refresh(); ctx.refresh();
ctx.getBean(L0ConfigLight.class); S1Config config = ctx.getBean(S1Config.class);
ctx.getBean("l0Bean"); assertTrue(config != ctx.getBean(S1Config.class));
TestBean tb = ctx.getBean("l0Bean", TestBean.class);
assertTrue(tb == ctx.getBean("l0Bean", TestBean.class));
ctx.getBean(L0ConfigLight.L1ConfigLight.class); ctx.getBean(L0Config.L1Config.class);
ctx.getBean("l1Bean"); ctx.getBean("l1Bean");
ctx.getBean(L0ConfigLight.L1ConfigLight.L2ConfigLight.class); ctx.getBean(L0Config.L1Config.L2Config.class);
ctx.getBean("l2Bean"); ctx.getBean("l2Bean");
// ensure that override order is correct // ensure that override order is correct and that it is a singleton
assertThat(ctx.getBean("overrideBean", TestBean.class).getName(), is("override-l0")); TestBean ob = ctx.getBean("overrideBean", TestBean.class);
assertThat(ob.getName(), is("override-s1"));
assertTrue(ob == ctx.getBean("overrideBean", TestBean.class));
TestBean pb1 = ctx.getBean("prototypeBean", TestBean.class);
TestBean pb2 = ctx.getBean("prototypeBean", TestBean.class);
assertTrue(pb1 != pb2);
assertTrue(pb1.getFriends().iterator().next() != pb2.getFriends().iterator().next());
}
@Test
public void twoLevelsDeepWithInheritanceAndScopedProxy() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(S1ImporterWithProxy.class);
ctx.refresh();
S1ConfigWithProxy config = ctx.getBean(S1ConfigWithProxy.class);
assertTrue(config == ctx.getBean(S1ConfigWithProxy.class));
TestBean tb = ctx.getBean("l0Bean", TestBean.class);
assertTrue(tb == ctx.getBean("l0Bean", TestBean.class));
ctx.getBean(L0Config.L1Config.class);
ctx.getBean("l1Bean");
ctx.getBean(L0Config.L1Config.L2Config.class);
ctx.getBean("l2Bean");
// ensure that override order is correct and that it is a singleton
TestBean ob = ctx.getBean("overrideBean", TestBean.class);
assertThat(ob.getName(), is("override-s1"));
assertTrue(ob == ctx.getBean("overrideBean", TestBean.class));
TestBean pb1 = ctx.getBean("prototypeBean", TestBean.class);
TestBean pb2 = ctx.getBean("prototypeBean", TestBean.class);
assertTrue(pb1 != pb2);
assertTrue(pb1.getFriends().iterator().next() != pb2.getFriends().iterator().next());
} }
@Test @Test
@ -115,21 +186,34 @@ public class NestedConfigurationClassTests {
ctx.register(L0ConfigEmpty.class); ctx.register(L0ConfigEmpty.class);
ctx.refresh(); ctx.refresh();
ctx.getBean(L0ConfigEmpty.class); assertFalse(ctx.getBeanFactory().containsSingleton("l0ConfigEmpty"));
ctx.getBean(L0ConfigEmpty.L1ConfigEmpty.class); Object l0i1 = ctx.getBean(L0ConfigEmpty.class);
ctx.getBean(L0ConfigEmpty.L1ConfigEmpty.L2ConfigEmpty.class); Object l0i2 = ctx.getBean(L0ConfigEmpty.class);
assertTrue(l0i1 == l0i2);
Object l1i1 = ctx.getBean(L0ConfigEmpty.L1ConfigEmpty.class);
Object l1i2 = ctx.getBean(L0ConfigEmpty.L1ConfigEmpty.class);
assertTrue(l1i1 != l1i2);
Object l2i1 = ctx.getBean(L0ConfigEmpty.L1ConfigEmpty.L2ConfigEmpty.class);
Object l2i2 = ctx.getBean(L0ConfigEmpty.L1ConfigEmpty.L2ConfigEmpty.class);
assertTrue(l2i1 == l2i2);
assertNotEquals(l2i1.toString(), l2i2.toString());
} }
@Configuration @Configuration
@Lazy
static class L0Config { static class L0Config {
@Bean @Bean
@Lazy
public TestBean l0Bean() { public TestBean l0Bean() {
return new TestBean("l0"); return new TestBean("l0");
} }
@Bean @Bean
@Lazy
public TestBean overrideBean() { public TestBean overrideBean() {
return new TestBean("override-l0"); return new TestBean("override-l0");
} }
@ -148,14 +232,17 @@ public class NestedConfigurationClassTests {
} }
@Configuration @Configuration
@Lazy
protected static class L2Config { protected static class L2Config {
@Bean @Bean
@Lazy
public TestBean l2Bean() { public TestBean l2Bean() {
return new TestBean("l2"); return new TestBean("l2");
} }
@Bean @Bean
@Lazy
public TestBean overrideBean() { public TestBean overrideBean() {
return new TestBean("override-l2"); return new TestBean("override-l2");
} }
@ -165,14 +252,17 @@ public class NestedConfigurationClassTests {
@Component @Component
@Lazy
static class L0ConfigLight { static class L0ConfigLight {
@Bean @Bean
@Lazy
public TestBean l0Bean() { public TestBean l0Bean() {
return new TestBean("l0"); return new TestBean("l0");
} }
@Bean @Bean
@Lazy
public TestBean overrideBean() { public TestBean overrideBean() {
return new TestBean("override-l0"); return new TestBean("override-l0");
} }
@ -191,14 +281,17 @@ public class NestedConfigurationClassTests {
} }
@Component @Component
@Lazy
protected static class L2ConfigLight { protected static class L2ConfigLight {
@Bean @Bean
@Lazy
public TestBean l2Bean() { public TestBean l2Bean() {
return new TestBean("l2"); return new TestBean("l2");
} }
@Bean @Bean
@Lazy
public TestBean overrideBean() { public TestBean overrideBean() {
return new TestBean("override-l2"); return new TestBean("override-l2");
} }
@ -207,20 +300,8 @@ public class NestedConfigurationClassTests {
} }
@Component
static class L0ConfigEmpty {
@Component
static class L1ConfigEmpty {
@Component
protected static class L2ConfigEmpty {
}
}
}
@Configuration @Configuration
@Scope("prototype")
static class S1Config extends L0Config { static class S1Config extends L0Config {
@Override @Override
@ -228,6 +309,60 @@ public class NestedConfigurationClassTests {
public TestBean overrideBean() { public TestBean overrideBean() {
return new TestBean("override-s1"); return new TestBean("override-s1");
} }
@Bean
@Scope("prototype")
public TestBean prototypeBean() {
TestBean tb = new TestBean("override-s1");
tb.getFriends().add(this);
return tb;
}
}
@Configuration
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
static class S1ConfigWithProxy extends L0Config {
@Override
@Bean
public TestBean overrideBean() {
return new TestBean("override-s1");
}
@Bean
@Scope("prototype")
public TestBean prototypeBean() {
TestBean tb = new TestBean("override-s1");
tb.getFriends().add(this);
return tb;
}
}
@Import(S1Config.class)
static class S1Importer {
}
@Import(S1ConfigWithProxy.class)
static class S1ImporterWithProxy {
}
@Component
@Lazy
static class L0ConfigEmpty {
@Component
@Scope("prototype")
static class L1ConfigEmpty {
@Component
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
protected static class L2ConfigEmpty {
}
}
} }
} }