Skip to content

Commit 998da2f

Browse files
committed
Document destruction callback behavior for inner beans in case of scope mismatch
This commit undoes the previous refinement and rather documents the original behavior. Issue: SPR-13739
1 parent 8ed2c47 commit 998da2f

File tree

5 files changed

+50
-65
lines changed

5 files changed

+50
-65
lines changed

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,14 +1251,15 @@ protected RootBeanDefinition getMergedBeanDefinition(
12511251

12521252
// Set default singleton scope, if not configured before.
12531253
if (!StringUtils.hasLength(mbd.getScope())) {
1254-
mbd.setScope(BeanDefinition.SCOPE_SINGLETON);
1254+
mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
12551255
}
12561256

1257-
// Check for a mismatch between an inner bean's scope and its containing
1258-
// bean's scope: For example, a bean contained in a non-singleton bean
1259-
// cannot be a singleton itself. Let's correct this on the fly here.
1260-
if (containingBd != null && !mbd.isPrototype() && !mbd.getScope().equals(containingBd.getScope())) {
1261-
mbd.setScope(containingBd.isSingleton() ? BeanDefinition.SCOPE_PROTOTYPE : containingBd.getScope());
1257+
// A bean contained in a non-singleton bean cannot be a singleton itself.
1258+
// Let's correct this on the fly here, since this might be the result of
1259+
// parent-child merging for the outer bean, in which case the original inner bean
1260+
// definition will not have inherited the merged outer bean's singleton status.
1261+
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
1262+
mbd.setScope(containingBd.getScope());
12621263
}
12631264

12641265
// Only cache the merged bean definition if we're already about to create an

spring-beans/src/main/resources/org/springframework/beans/factory/xml/spring-beans-4.1.xsd

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
(or an ancestor factory).
3232
3333
As alternative to bean references, "inner bean definitions" can be used.
34-
Singleton flags of such inner bean definitions are effectively ignored:
35-
inner beans are typically anonymous prototypes.
34+
Such inner beans do not have an independent lifecycle; they are typically
35+
anonymous nested objects that share the scope of their containing bean.
3636
3737
There is also support for lists, sets, maps, and java.util.Properties
3838
as bean property types or constructor argument types.
@@ -113,24 +113,29 @@
113113
<xsd:annotation>
114114
<xsd:documentation><![CDATA[
115115
The default 'lazy-init' value; see the documentation for the
116-
'lazy-init' attribute of the 'bean' element.
116+
'lazy-init' attribute of the 'bean' element. The default is "default",
117+
indicating inheritance from outer 'beans' sections in case of nesting,
118+
otherwise falling back to "false".
117119
]]></xsd:documentation>
118120
</xsd:annotation>
119121
</xsd:attribute>
120122
<xsd:attribute name="default-merge" default="default" type="defaultable-boolean">
121123
<xsd:annotation>
122124
<xsd:documentation><![CDATA[
123-
The default 'merge' value; see the documentation for the
124-
'merge' attribute of the various collection elements. The default
125-
is 'false'.
125+
The default 'merge' value; see the documentation for the 'merge'
126+
attribute of the various collection elements. The default is "default",
127+
indicating inheritance from outer 'beans' sections in case of nesting,
128+
otherwise falling back to "false".
126129
]]></xsd:documentation>
127130
</xsd:annotation>
128131
</xsd:attribute>
129132
<xsd:attribute name="default-autowire" default="default">
130133
<xsd:annotation>
131134
<xsd:documentation><![CDATA[
132135
The default 'autowire' value; see the documentation for the
133-
'autowire' attribute of the 'bean' element. The default is 'default'.
136+
'autowire' attribute of the 'bean' element. The default is "default",
137+
indicating inheritance from outer 'beans' sections in case of nesting,
138+
otherwise falling back to "no" (i.e. no externally driven autowiring).
134139
]]></xsd:documentation>
135140
</xsd:annotation>
136141
<xsd:simpleType>
@@ -305,10 +310,10 @@
305310
service objects. Further scopes, such as "request" or "session", might
306311
be supported by extended bean factories (e.g. in a web environment).
307312
308-
Inner bean definitions inherit the singleton status of their containing
309-
bean definition, unless explicitly specified: The inner bean will be a
313+
Inner bean definitions inherit the scope of their containing bean
314+
definition, unless explicitly specified: The inner bean will be a
310315
singleton if the containing bean is a singleton, and a prototype if
311-
the containing bean has any other scope.
316+
the containing bean is a prototype, etc.
312317
]]></xsd:documentation>
313318
</xsd:annotation>
314319
</xsd:attribute>
@@ -328,13 +333,15 @@
328333
<xsd:attribute name="lazy-init" default="default" type="defaultable-boolean">
329334
<xsd:annotation>
330335
<xsd:documentation><![CDATA[
331-
Indicates whether or not this bean is to be lazily initialized.
332-
If false, it will be instantiated on startup by bean factories
333-
that perform eager initialization of singletons. The default is
334-
"false".
336+
Indicates whether this bean is to be lazily initialized. If "false",
337+
it will be instantiated on startup by bean factories that perform eager
338+
initialization of singletons. The effective default is "false".
335339
336340
Note: This attribute will not be inherited by child bean definitions.
337-
Hence, it needs to be specified per concrete bean definition.
341+
Hence, it needs to be specified per concrete bean definition. It can be
342+
shared through the 'default-lazy-init' attribute at the 'beans' level
343+
and potentially inherited from outer 'beans' defaults in case of nested
344+
'beans' sections (e.g. with different profiles).
338345
]]></xsd:documentation>
339346
</xsd:annotation>
340347
</xsd:attribute>
@@ -344,7 +351,7 @@
344351
Controls whether bean properties are "autowired".
345352
This is an automagical process in which bean references don't need
346353
to be coded explicitly in the XML bean definition file, but rather the
347-
Spring container works out dependencies.
354+
Spring container works out dependencies. The effective default is "no".
348355
349356
There are 4 modes:
350357
@@ -379,7 +386,10 @@
379386
elements, always override autowiring.
380387
381388
Note: This attribute will not be inherited by child bean definitions.
382-
Hence, it needs to be specified per concrete bean definition.
389+
Hence, it needs to be specified per concrete bean definition. It can be
390+
shared through the 'default-autowire' attribute at the 'beans' level
391+
and potentially inherited from outer 'beans' defaults in case of nested
392+
'beans' sections (e.g. with different profiles).
383393
]]></xsd:documentation>
384394
</xsd:annotation>
385395
<xsd:simpleType>

spring-beans/src/main/resources/org/springframework/beans/factory/xml/spring-beans-4.2.xsd

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
(or an ancestor factory).
3232
3333
As alternative to bean references, "inner bean definitions" can be used.
34-
Singleton flags of such inner bean definitions are effectively ignored:
35-
inner beans are typically anonymous prototypes.
34+
Such inner beans do not have an independent lifecycle; they are typically
35+
anonymous nested objects that share the scope of their containing bean.
3636
3737
There is also support for lists, sets, maps, and java.util.Properties
3838
as bean property types or constructor argument types.
@@ -310,10 +310,10 @@
310310
service objects. Further scopes, such as "request" or "session", might
311311
be supported by extended bean factories (e.g. in a web environment).
312312
313-
Inner bean definitions inherit the singleton status of their containing
314-
bean definition, unless explicitly specified: The inner bean will be a
313+
Inner bean definitions inherit the scope of their containing bean
314+
definition, unless explicitly specified: The inner bean will be a
315315
singleton if the containing bean is a singleton, and a prototype if
316-
the containing bean has any other scope.
316+
the containing bean is a prototype, etc.
317317
]]></xsd:documentation>
318318
</xsd:annotation>
319319
</xsd:attribute>

spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2548,39 +2548,6 @@ public void testDestroyMethodOnInnerBeanAsPrototype() {
25482548
assertEquals("Destroy methods invoked", 1, BeanWithDestroyMethod.closeCount);
25492549
}
25502550

2551-
@Test
2552-
public void testDestroyMethodOnInnerBeanAsCustomScope() {
2553-
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
2554-
RootBeanDefinition innerBd = new RootBeanDefinition(BeanWithDestroyMethod.class);
2555-
innerBd.setScope("custom");
2556-
innerBd.setDestroyMethodName("close");
2557-
RootBeanDefinition bd = new RootBeanDefinition(BeanWithDestroyMethod.class);
2558-
bd.setDestroyMethodName("close");
2559-
bd.getPropertyValues().add("inner", innerBd);
2560-
lbf.registerBeanDefinition("test", bd);
2561-
BeanWithDestroyMethod.closeCount = 0;
2562-
lbf.preInstantiateSingletons();
2563-
lbf.destroySingletons();
2564-
assertEquals("Destroy methods not invoked", 1, BeanWithDestroyMethod.closeCount);
2565-
}
2566-
2567-
@Test
2568-
public void testDestroyMethodOnInnerBeanAsCustomScopeWithinPrototype() {
2569-
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
2570-
RootBeanDefinition innerBd = new RootBeanDefinition(BeanWithDestroyMethod.class);
2571-
innerBd.setScope("custom");
2572-
innerBd.setDestroyMethodName("close");
2573-
RootBeanDefinition bd = new RootBeanDefinition(BeanWithDestroyMethod.class);
2574-
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
2575-
bd.setDestroyMethodName("close");
2576-
bd.getPropertyValues().add("inner", innerBd);
2577-
lbf.registerBeanDefinition("test", bd);
2578-
BeanWithDestroyMethod.closeCount = 0;
2579-
Object prototypeInstance = lbf.getBean("test");
2580-
lbf.destroyBean("test", prototypeInstance);
2581-
assertEquals("Destroy methods not invoked", 1, BeanWithDestroyMethod.closeCount);
2582-
}
2583-
25842551
@Test
25852552
public void testFindTypeOfSingletonFactoryMethodOnBeanInstance() {
25862553
findTypeOfPrototypeFactoryMethodOnBeanInstance(true);

src/asciidoc/core-beans.adoc

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1397,10 +1397,17 @@ so-called __inner bean__.
13971397
</bean>
13981398
----
13991399

1400-
An inner bean definition does not require a defined id or name; the container ignores
1401-
these values. It also ignores the `scope` flag. Inner beans are __always__ anonymous and
1402-
they are __always__ created with the outer bean. It is __not__ possible to inject inner
1403-
beans into collaborating beans other than into the enclosing bean.
1400+
An inner bean definition does not require a defined id or name; if specified, the container
1401+
does not use such a value as an identifier. The container also ignores the `scope` flag on
1402+
creation: Inner beans are __always__ anonymous and they are __always__ created with the outer
1403+
bean. It is __not__ possible to inject inner beans into collaborating beans other than into
1404+
the enclosing bean or to access them independently.
1405+
1406+
As a corner case, it is possible to receive destruction callbacks from a custom scope, e.g.
1407+
for a request-scoped inner bean contained within a singleton bean: The creation of the inner
1408+
bean instance will be tied to its containing bean, but destruction callbacks allow it to
1409+
participate in the request scope's lifecycle. This is not a common scenario; inner beans
1410+
typically simply share their containing bean's scope.
14041411

14051412

14061413
[[beans-collection-elements]]

0 commit comments

Comments
 (0)