Skip to content

Commit 5308b3e

Browse files
committed
Revised naming for prototype inner beans to avoid excessive unique name calculation
Restored original singleton-only adaptInnerBeanName behavior, avoiding endless unique name calculation for every single prototype instance. Non-named inner BeanDefinition objects now suffixed with an identity hex code analogous to non-named XML bean definitions, largely avoiding naming collisions to begin with. After SPR-11246, post-processors can deal with unstable classes per bean name, so occasional collisions aren't a hard problem anymore. Issue: SPR-11545
1 parent 9dcd03d commit 5308b3e

File tree

3 files changed

+37
-7
lines changed

3 files changed

+37
-7
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionValueResolver.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -81,6 +81,7 @@ public BeanDefinitionValueResolver(
8181
this.typeConverter = typeConverter;
8282
}
8383

84+
8485
/**
8586
* Given a PropertyValue, return a value, resolving any references to other
8687
* beans in the factory if necessary. The value could be:
@@ -123,7 +124,9 @@ else if (value instanceof BeanDefinitionHolder) {
123124
else if (value instanceof BeanDefinition) {
124125
// Resolve plain BeanDefinition, without contained name: use dummy name.
125126
BeanDefinition bd = (BeanDefinition) value;
126-
return resolveInnerBean(argName, "(inner bean)", bd);
127+
String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR +
128+
ObjectUtils.getIdentityHexString(bd);
129+
return resolveInnerBean(argName, innerBeanName, bd);
127130
}
128131
else if (value instanceof ManagedArray) {
129132
// May need to resolve contained runtime references.
@@ -256,20 +259,25 @@ private Object resolveInnerBean(Object argName, String innerBeanName, BeanDefini
256259
mbd = this.beanFactory.getMergedBeanDefinition(innerBeanName, innerBd, this.beanDefinition);
257260
// Check given bean name whether it is unique. If not already unique,
258261
// add counter - increasing the counter until the name is unique.
259-
String actualInnerBeanName = adaptInnerBeanName(innerBeanName);
262+
String actualInnerBeanName = innerBeanName;
263+
if (mbd.isSingleton()) {
264+
actualInnerBeanName = adaptInnerBeanName(innerBeanName);
265+
}
260266
this.beanFactory.registerContainedBean(actualInnerBeanName, this.beanName);
261267
// Guarantee initialization of beans that the inner bean depends on.
262268
String[] dependsOn = mbd.getDependsOn();
263269
if (dependsOn != null) {
264270
for (String dependsOnBean : dependsOn) {
265-
this.beanFactory.getBean(dependsOnBean);
266271
this.beanFactory.registerDependentBean(dependsOnBean, actualInnerBeanName);
272+
this.beanFactory.getBean(dependsOnBean);
267273
}
268274
}
275+
// Actually create the inner bean instance now...
269276
Object innerBean = this.beanFactory.createBean(actualInnerBeanName, mbd, null);
270277
if (innerBean instanceof FactoryBean) {
271278
boolean synthetic = mbd.isSynthetic();
272-
return this.beanFactory.getObjectFromFactoryBean((FactoryBean<?>) innerBean, actualInnerBeanName, !synthetic);
279+
return this.beanFactory.getObjectFromFactoryBean(
280+
(FactoryBean<?>) innerBean, actualInnerBeanName, !synthetic);
273281
}
274282
else {
275283
return innerBean;

spring-context/src/test/java/org/springframework/beans/factory/xml/XmlBeanFactoryTests-reftypes.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,15 @@
129129
</constructor-arg>
130130
</bean>
131131

132+
<bean id="hasInnerBeansAsPrototype" class="org.springframework.tests.sample.beans.TestBean" scope="prototype">
133+
<constructor-arg>
134+
<bean id="innerBean" class="org.springframework.tests.sample.beans.TestBean" destroy-method="destroy">
135+
<constructor-arg><value>inner1</value></constructor-arg>
136+
<constructor-arg type="int"><value>6</value></constructor-arg>
137+
</bean>
138+
</constructor-arg>
139+
</bean>
140+
132141
<bean id="hasInnerBeansWithoutDestroy" class="org.springframework.tests.sample.beans.TestBean">
133142
<constructor-arg><value>hasInner</value></constructor-arg>
134143
<constructor-arg index="1" type="int"><value>5</value></constructor-arg>

spring-context/src/test/java/org/springframework/beans/factory/xml/XmlBeanFactoryTests.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
import java.util.Map;
2828

2929
import org.apache.commons.logging.LogFactory;
30-
3130
import org.junit.Test;
31+
import org.xml.sax.InputSource;
3232

3333
import org.springframework.aop.framework.ProxyFactory;
3434
import org.springframework.aop.support.AopUtils;
@@ -65,7 +65,6 @@
6565
import org.springframework.util.FileCopyUtils;
6666
import org.springframework.util.SerializationTestUtils;
6767
import org.springframework.util.StopWatch;
68-
import org.xml.sax.InputSource;
6968

7069
import static org.hamcrest.CoreMatchers.*;
7170
import static org.junit.Assert.*;
@@ -229,6 +228,20 @@ public void testInnerBeans() throws IOException {
229228
assertEquals("inner1", innerForConstructor.getName());
230229
assertEquals(6, innerForConstructor.getAge());
231230

231+
hasInnerBeansForConstructor = (TestBean) xbf.getBean("hasInnerBeansAsPrototype");
232+
innerForConstructor = (TestBean) hasInnerBeansForConstructor.getSpouse();
233+
assertNotNull(innerForConstructor);
234+
assertEquals("innerBean", innerForConstructor.getBeanName());
235+
assertEquals("inner1", innerForConstructor.getName());
236+
assertEquals(6, innerForConstructor.getAge());
237+
238+
hasInnerBeansForConstructor = (TestBean) xbf.getBean("hasInnerBeansAsPrototype");
239+
innerForConstructor = (TestBean) hasInnerBeansForConstructor.getSpouse();
240+
assertNotNull(innerForConstructor);
241+
assertEquals("innerBean", innerForConstructor.getBeanName());
242+
assertEquals("inner1", innerForConstructor.getName());
243+
assertEquals(6, innerForConstructor.getAge());
244+
232245
xbf.destroySingletons();
233246
assertTrue(inner1.wasDestroyed());
234247
assertTrue(inner2.wasDestroyed());

0 commit comments

Comments
 (0)