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
This commit is contained in:
@@ -1251,14 +1251,15 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||
|
||||
// Set default singleton scope, if not configured before.
|
||||
if (!StringUtils.hasLength(mbd.getScope())) {
|
||||
mbd.setScope(BeanDefinition.SCOPE_SINGLETON);
|
||||
mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
|
||||
}
|
||||
|
||||
// Check for a mismatch between an inner bean's scope and its containing
|
||||
// bean's scope: For example, a bean contained in a non-singleton bean
|
||||
// cannot be a singleton itself. Let's correct this on the fly here.
|
||||
if (containingBd != null && !mbd.isPrototype() && !mbd.getScope().equals(containingBd.getScope())) {
|
||||
mbd.setScope(containingBd.isSingleton() ? BeanDefinition.SCOPE_PROTOTYPE : containingBd.getScope());
|
||||
// A bean contained in a non-singleton bean cannot be a singleton itself.
|
||||
// Let's correct this on the fly here, since this might be the result of
|
||||
// parent-child merging for the outer bean, in which case the original inner bean
|
||||
// definition will not have inherited the merged outer bean's singleton status.
|
||||
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
|
||||
mbd.setScope(containingBd.getScope());
|
||||
}
|
||||
|
||||
// Only cache the merged bean definition if we're already about to create an
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
(or an ancestor factory).
|
||||
|
||||
As alternative to bean references, "inner bean definitions" can be used.
|
||||
Singleton flags of such inner bean definitions are effectively ignored:
|
||||
inner beans are typically anonymous prototypes.
|
||||
Such inner beans do not have an independent lifecycle; they are typically
|
||||
anonymous nested objects that share the scope of their containing bean.
|
||||
|
||||
There is also support for lists, sets, maps, and java.util.Properties
|
||||
as bean property types or constructor argument types.
|
||||
@@ -113,16 +113,19 @@
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The default 'lazy-init' value; see the documentation for the
|
||||
'lazy-init' attribute of the 'bean' element.
|
||||
'lazy-init' attribute of the 'bean' element. The default is "default",
|
||||
indicating inheritance from outer 'beans' sections in case of nesting,
|
||||
otherwise falling back to "false".
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="default-merge" default="default" type="defaultable-boolean">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The default 'merge' value; see the documentation for the
|
||||
'merge' attribute of the various collection elements. The default
|
||||
is 'false'.
|
||||
The default 'merge' value; see the documentation for the 'merge'
|
||||
attribute of the various collection elements. The default is "default",
|
||||
indicating inheritance from outer 'beans' sections in case of nesting,
|
||||
otherwise falling back to "false".
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
@@ -130,7 +133,9 @@
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The default 'autowire' value; see the documentation for the
|
||||
'autowire' attribute of the 'bean' element. The default is 'default'.
|
||||
'autowire' attribute of the 'bean' element. The default is "default",
|
||||
indicating inheritance from outer 'beans' sections in case of nesting,
|
||||
otherwise falling back to "no" (i.e. no externally driven autowiring).
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
@@ -305,10 +310,10 @@
|
||||
service objects. Further scopes, such as "request" or "session", might
|
||||
be supported by extended bean factories (e.g. in a web environment).
|
||||
|
||||
Inner bean definitions inherit the singleton status of their containing
|
||||
bean definition, unless explicitly specified: The inner bean will be a
|
||||
Inner bean definitions inherit the scope of their containing bean
|
||||
definition, unless explicitly specified: The inner bean will be a
|
||||
singleton if the containing bean is a singleton, and a prototype if
|
||||
the containing bean has any other scope.
|
||||
the containing bean is a prototype, etc.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
@@ -328,13 +333,15 @@
|
||||
<xsd:attribute name="lazy-init" default="default" type="defaultable-boolean">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Indicates whether or not this bean is to be lazily initialized.
|
||||
If false, it will be instantiated on startup by bean factories
|
||||
that perform eager initialization of singletons. The default is
|
||||
"false".
|
||||
Indicates whether this bean is to be lazily initialized. If "false",
|
||||
it will be instantiated on startup by bean factories that perform eager
|
||||
initialization of singletons. The effective default is "false".
|
||||
|
||||
Note: This attribute will not be inherited by child bean definitions.
|
||||
Hence, it needs to be specified per concrete bean definition.
|
||||
Hence, it needs to be specified per concrete bean definition. It can be
|
||||
shared through the 'default-lazy-init' attribute at the 'beans' level
|
||||
and potentially inherited from outer 'beans' defaults in case of nested
|
||||
'beans' sections (e.g. with different profiles).
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
@@ -344,7 +351,7 @@
|
||||
Controls whether bean properties are "autowired".
|
||||
This is an automagical process in which bean references don't need
|
||||
to be coded explicitly in the XML bean definition file, but rather the
|
||||
Spring container works out dependencies.
|
||||
Spring container works out dependencies. The effective default is "no".
|
||||
|
||||
There are 4 modes:
|
||||
|
||||
@@ -379,7 +386,10 @@
|
||||
elements, always override autowiring.
|
||||
|
||||
Note: This attribute will not be inherited by child bean definitions.
|
||||
Hence, it needs to be specified per concrete bean definition.
|
||||
Hence, it needs to be specified per concrete bean definition. It can be
|
||||
shared through the 'default-autowire' attribute at the 'beans' level
|
||||
and potentially inherited from outer 'beans' defaults in case of nested
|
||||
'beans' sections (e.g. with different profiles).
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
(or an ancestor factory).
|
||||
|
||||
As alternative to bean references, "inner bean definitions" can be used.
|
||||
Singleton flags of such inner bean definitions are effectively ignored:
|
||||
inner beans are typically anonymous prototypes.
|
||||
Such inner beans do not have an independent lifecycle; they are typically
|
||||
anonymous nested objects that share the scope of their containing bean.
|
||||
|
||||
There is also support for lists, sets, maps, and java.util.Properties
|
||||
as bean property types or constructor argument types.
|
||||
@@ -310,10 +310,10 @@
|
||||
service objects. Further scopes, such as "request" or "session", might
|
||||
be supported by extended bean factories (e.g. in a web environment).
|
||||
|
||||
Inner bean definitions inherit the singleton status of their containing
|
||||
bean definition, unless explicitly specified: The inner bean will be a
|
||||
Inner bean definitions inherit the scope of their containing bean
|
||||
definition, unless explicitly specified: The inner bean will be a
|
||||
singleton if the containing bean is a singleton, and a prototype if
|
||||
the containing bean has any other scope.
|
||||
the containing bean is a prototype, etc.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
|
||||
@@ -2548,39 +2548,6 @@ public class DefaultListableBeanFactoryTests {
|
||||
assertEquals("Destroy methods invoked", 1, BeanWithDestroyMethod.closeCount);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDestroyMethodOnInnerBeanAsCustomScope() {
|
||||
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
RootBeanDefinition innerBd = new RootBeanDefinition(BeanWithDestroyMethod.class);
|
||||
innerBd.setScope("custom");
|
||||
innerBd.setDestroyMethodName("close");
|
||||
RootBeanDefinition bd = new RootBeanDefinition(BeanWithDestroyMethod.class);
|
||||
bd.setDestroyMethodName("close");
|
||||
bd.getPropertyValues().add("inner", innerBd);
|
||||
lbf.registerBeanDefinition("test", bd);
|
||||
BeanWithDestroyMethod.closeCount = 0;
|
||||
lbf.preInstantiateSingletons();
|
||||
lbf.destroySingletons();
|
||||
assertEquals("Destroy methods not invoked", 1, BeanWithDestroyMethod.closeCount);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDestroyMethodOnInnerBeanAsCustomScopeWithinPrototype() {
|
||||
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
RootBeanDefinition innerBd = new RootBeanDefinition(BeanWithDestroyMethod.class);
|
||||
innerBd.setScope("custom");
|
||||
innerBd.setDestroyMethodName("close");
|
||||
RootBeanDefinition bd = new RootBeanDefinition(BeanWithDestroyMethod.class);
|
||||
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
||||
bd.setDestroyMethodName("close");
|
||||
bd.getPropertyValues().add("inner", innerBd);
|
||||
lbf.registerBeanDefinition("test", bd);
|
||||
BeanWithDestroyMethod.closeCount = 0;
|
||||
Object prototypeInstance = lbf.getBean("test");
|
||||
lbf.destroyBean("test", prototypeInstance);
|
||||
assertEquals("Destroy methods not invoked", 1, BeanWithDestroyMethod.closeCount);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindTypeOfSingletonFactoryMethodOnBeanInstance() {
|
||||
findTypeOfPrototypeFactoryMethodOnBeanInstance(true);
|
||||
|
||||
@@ -1397,10 +1397,17 @@ so-called __inner bean__.
|
||||
</bean>
|
||||
----
|
||||
|
||||
An inner bean definition does not require a defined id or name; the container ignores
|
||||
these values. It also ignores the `scope` flag. Inner beans are __always__ anonymous and
|
||||
they are __always__ created with the outer bean. It is __not__ possible to inject inner
|
||||
beans into collaborating beans other than into the enclosing bean.
|
||||
An inner bean definition does not require a defined id or name; if specified, the container
|
||||
does not use such a value as an identifier. The container also ignores the `scope` flag on
|
||||
creation: Inner beans are __always__ anonymous and they are __always__ created with the outer
|
||||
bean. It is __not__ possible to inject inner beans into collaborating beans other than into
|
||||
the enclosing bean or to access them independently.
|
||||
|
||||
As a corner case, it is possible to receive destruction callbacks from a custom scope, e.g.
|
||||
for a request-scoped inner bean contained within a singleton bean: The creation of the inner
|
||||
bean instance will be tied to its containing bean, but destruction callbacks allow it to
|
||||
participate in the request scope's lifecycle. This is not a common scenario; inner beans
|
||||
typically simply share their containing bean's scope.
|
||||
|
||||
|
||||
[[beans-collection-elements]]
|
||||
|
||||
Reference in New Issue
Block a user