diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java index 995be594f2..cddecfc3b1 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java @@ -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 diff --git a/spring-beans/src/main/resources/org/springframework/beans/factory/xml/spring-beans-4.1.xsd b/spring-beans/src/main/resources/org/springframework/beans/factory/xml/spring-beans-4.1.xsd index 9a9cb52bb1..8dfe6d25f2 100644 --- a/spring-beans/src/main/resources/org/springframework/beans/factory/xml/spring-beans-4.1.xsd +++ b/spring-beans/src/main/resources/org/springframework/beans/factory/xml/spring-beans-4.1.xsd @@ -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 @@ @@ -130,7 +133,9 @@ @@ -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. ]]> @@ -328,13 +333,15 @@ @@ -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). ]]> diff --git a/spring-beans/src/main/resources/org/springframework/beans/factory/xml/spring-beans-4.2.xsd b/spring-beans/src/main/resources/org/springframework/beans/factory/xml/spring-beans-4.2.xsd index c77e0250e1..4064c7bc0d 100644 --- a/spring-beans/src/main/resources/org/springframework/beans/factory/xml/spring-beans-4.2.xsd +++ b/spring-beans/src/main/resources/org/springframework/beans/factory/xml/spring-beans-4.2.xsd @@ -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. ]]> diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java index 14ad5c1488..c7c5876585 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java @@ -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); diff --git a/src/asciidoc/core-beans.adoc b/src/asciidoc/core-beans.adoc index caa564f872..6c2a61c157 100644 --- a/src/asciidoc/core-beans.adoc +++ b/src/asciidoc/core-beans.adoc @@ -1397,10 +1397,17 @@ so-called __inner 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]]