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.
|
// Set default singleton scope, if not configured before.
|
||||||
if (!StringUtils.hasLength(mbd.getScope())) {
|
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
|
// A bean contained in a non-singleton bean cannot be a singleton itself.
|
||||||
// bean's scope: For example, a bean contained in a non-singleton bean
|
// Let's correct this on the fly here, since this might be the result of
|
||||||
// cannot be a singleton itself. Let's correct this on the fly here.
|
// parent-child merging for the outer bean, in which case the original inner bean
|
||||||
if (containingBd != null && !mbd.isPrototype() && !mbd.getScope().equals(containingBd.getScope())) {
|
// definition will not have inherited the merged outer bean's singleton status.
|
||||||
mbd.setScope(containingBd.isSingleton() ? BeanDefinition.SCOPE_PROTOTYPE : containingBd.getScope());
|
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
|
// Only cache the merged bean definition if we're already about to create an
|
||||||
|
|||||||
@@ -31,8 +31,8 @@
|
|||||||
(or an ancestor factory).
|
(or an ancestor factory).
|
||||||
|
|
||||||
As alternative to bean references, "inner bean definitions" can be used.
|
As alternative to bean references, "inner bean definitions" can be used.
|
||||||
Singleton flags of such inner bean definitions are effectively ignored:
|
Such inner beans do not have an independent lifecycle; they are typically
|
||||||
inner beans are typically anonymous prototypes.
|
anonymous nested objects that share the scope of their containing bean.
|
||||||
|
|
||||||
There is also support for lists, sets, maps, and java.util.Properties
|
There is also support for lists, sets, maps, and java.util.Properties
|
||||||
as bean property types or constructor argument types.
|
as bean property types or constructor argument types.
|
||||||
@@ -113,16 +113,19 @@
|
|||||||
<xsd:annotation>
|
<xsd:annotation>
|
||||||
<xsd:documentation><![CDATA[
|
<xsd:documentation><![CDATA[
|
||||||
The default 'lazy-init' value; see the documentation for the
|
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:documentation>
|
||||||
</xsd:annotation>
|
</xsd:annotation>
|
||||||
</xsd:attribute>
|
</xsd:attribute>
|
||||||
<xsd:attribute name="default-merge" default="default" type="defaultable-boolean">
|
<xsd:attribute name="default-merge" default="default" type="defaultable-boolean">
|
||||||
<xsd:annotation>
|
<xsd:annotation>
|
||||||
<xsd:documentation><![CDATA[
|
<xsd:documentation><![CDATA[
|
||||||
The default 'merge' value; see the documentation for the
|
The default 'merge' value; see the documentation for the 'merge'
|
||||||
'merge' attribute of the various collection elements. The default
|
attribute of the various collection elements. The default is "default",
|
||||||
is 'false'.
|
indicating inheritance from outer 'beans' sections in case of nesting,
|
||||||
|
otherwise falling back to "false".
|
||||||
]]></xsd:documentation>
|
]]></xsd:documentation>
|
||||||
</xsd:annotation>
|
</xsd:annotation>
|
||||||
</xsd:attribute>
|
</xsd:attribute>
|
||||||
@@ -130,7 +133,9 @@
|
|||||||
<xsd:annotation>
|
<xsd:annotation>
|
||||||
<xsd:documentation><![CDATA[
|
<xsd:documentation><![CDATA[
|
||||||
The default 'autowire' value; see the documentation for the
|
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:documentation>
|
||||||
</xsd:annotation>
|
</xsd:annotation>
|
||||||
<xsd:simpleType>
|
<xsd:simpleType>
|
||||||
@@ -305,10 +310,10 @@
|
|||||||
service objects. Further scopes, such as "request" or "session", might
|
service objects. Further scopes, such as "request" or "session", might
|
||||||
be supported by extended bean factories (e.g. in a web environment).
|
be supported by extended bean factories (e.g. in a web environment).
|
||||||
|
|
||||||
Inner bean definitions inherit the singleton status of their containing
|
Inner bean definitions inherit the scope of their containing bean
|
||||||
bean definition, unless explicitly specified: The inner bean will be a
|
definition, unless explicitly specified: The inner bean will be a
|
||||||
singleton if the containing bean is a singleton, and a prototype if
|
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:documentation>
|
||||||
</xsd:annotation>
|
</xsd:annotation>
|
||||||
</xsd:attribute>
|
</xsd:attribute>
|
||||||
@@ -328,13 +333,15 @@
|
|||||||
<xsd:attribute name="lazy-init" default="default" type="defaultable-boolean">
|
<xsd:attribute name="lazy-init" default="default" type="defaultable-boolean">
|
||||||
<xsd:annotation>
|
<xsd:annotation>
|
||||||
<xsd:documentation><![CDATA[
|
<xsd:documentation><![CDATA[
|
||||||
Indicates whether or not this bean is to be lazily initialized.
|
Indicates whether this bean is to be lazily initialized. If "false",
|
||||||
If false, it will be instantiated on startup by bean factories
|
it will be instantiated on startup by bean factories that perform eager
|
||||||
that perform eager initialization of singletons. The default is
|
initialization of singletons. The effective default is "false".
|
||||||
"false".
|
|
||||||
|
|
||||||
Note: This attribute will not be inherited by child bean definitions.
|
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:documentation>
|
||||||
</xsd:annotation>
|
</xsd:annotation>
|
||||||
</xsd:attribute>
|
</xsd:attribute>
|
||||||
@@ -344,7 +351,7 @@
|
|||||||
Controls whether bean properties are "autowired".
|
Controls whether bean properties are "autowired".
|
||||||
This is an automagical process in which bean references don't need
|
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
|
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:
|
There are 4 modes:
|
||||||
|
|
||||||
@@ -379,7 +386,10 @@
|
|||||||
elements, always override autowiring.
|
elements, always override autowiring.
|
||||||
|
|
||||||
Note: This attribute will not be inherited by child bean definitions.
|
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:documentation>
|
||||||
</xsd:annotation>
|
</xsd:annotation>
|
||||||
<xsd:simpleType>
|
<xsd:simpleType>
|
||||||
|
|||||||
@@ -31,8 +31,8 @@
|
|||||||
(or an ancestor factory).
|
(or an ancestor factory).
|
||||||
|
|
||||||
As alternative to bean references, "inner bean definitions" can be used.
|
As alternative to bean references, "inner bean definitions" can be used.
|
||||||
Singleton flags of such inner bean definitions are effectively ignored:
|
Such inner beans do not have an independent lifecycle; they are typically
|
||||||
inner beans are typically anonymous prototypes.
|
anonymous nested objects that share the scope of their containing bean.
|
||||||
|
|
||||||
There is also support for lists, sets, maps, and java.util.Properties
|
There is also support for lists, sets, maps, and java.util.Properties
|
||||||
as bean property types or constructor argument types.
|
as bean property types or constructor argument types.
|
||||||
@@ -310,10 +310,10 @@
|
|||||||
service objects. Further scopes, such as "request" or "session", might
|
service objects. Further scopes, such as "request" or "session", might
|
||||||
be supported by extended bean factories (e.g. in a web environment).
|
be supported by extended bean factories (e.g. in a web environment).
|
||||||
|
|
||||||
Inner bean definitions inherit the singleton status of their containing
|
Inner bean definitions inherit the scope of their containing bean
|
||||||
bean definition, unless explicitly specified: The inner bean will be a
|
definition, unless explicitly specified: The inner bean will be a
|
||||||
singleton if the containing bean is a singleton, and a prototype if
|
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:documentation>
|
||||||
</xsd:annotation>
|
</xsd:annotation>
|
||||||
</xsd:attribute>
|
</xsd:attribute>
|
||||||
|
|||||||
@@ -2548,39 +2548,6 @@ public class DefaultListableBeanFactoryTests {
|
|||||||
assertEquals("Destroy methods invoked", 1, BeanWithDestroyMethod.closeCount);
|
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
|
@Test
|
||||||
public void testFindTypeOfSingletonFactoryMethodOnBeanInstance() {
|
public void testFindTypeOfSingletonFactoryMethodOnBeanInstance() {
|
||||||
findTypeOfPrototypeFactoryMethodOnBeanInstance(true);
|
findTypeOfPrototypeFactoryMethodOnBeanInstance(true);
|
||||||
|
|||||||
@@ -1397,10 +1397,17 @@ so-called __inner bean__.
|
|||||||
</bean>
|
</bean>
|
||||||
----
|
----
|
||||||
|
|
||||||
An inner bean definition does not require a defined id or name; the container ignores
|
An inner bean definition does not require a defined id or name; if specified, the container
|
||||||
these values. It also ignores the `scope` flag. Inner beans are __always__ anonymous and
|
does not use such a value as an identifier. The container also ignores the `scope` flag on
|
||||||
they are __always__ created with the outer bean. It is __not__ possible to inject inner
|
creation: Inner beans are __always__ anonymous and they are __always__ created with the outer
|
||||||
beans into collaborating beans other than into the enclosing bean.
|
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]]
|
[[beans-collection-elements]]
|
||||||
|
|||||||
Reference in New Issue
Block a user