From fa0ef2d87e80257f5838676313a373661192a90d Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 1 Dec 2014 19:05:26 +0100 Subject: [PATCH] BeanFactory accepts getBean arguments for non-prototype beans as well Issue: SPR-12488 --- .../beans/factory/BeanFactory.java | 7 +++-- .../AbstractAutowireCapableBeanFactory.java | 6 ++-- .../factory/support/AbstractBeanFactory.java | 28 ++++++----------- .../ConfigurationClassPostProcessorTests.java | 30 +++++++++++++++++-- 4 files changed, 43 insertions(+), 28 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java index 428999cd7b..61b34cb64e 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java @@ -170,7 +170,8 @@ public interface BeanFactory { *

Allows for specifying explicit constructor arguments / factory method arguments, * overriding the specified default arguments (if any) in the bean definition. * @param name the name of the bean to retrieve - * @param args arguments to use if creating a prototype using explicit arguments + * @param args arguments to use when creating a bean instance using explicit arguments + * (only applied when creating a new instance as opposed to retrieving an existing one) * @return an instance of the bean * @throws NoSuchBeanDefinitionException if there is no such bean definition * @throws BeanDefinitionStoreException if arguments have been given but @@ -190,8 +191,8 @@ public interface BeanFactory { * but may also be translated into a conventional by-name lookup based on the name * of the given type. For more extensive retrieval operations across sets of beans, * use {@link ListableBeanFactory} and/or {@link BeanFactoryUtils}. - * @param args arguments to use if creating a prototype using explicit arguments to a - * static factory method. It is invalid to use a non-null args value in any other case. + * @param args arguments to use when creating a bean instance using explicit arguments + * (only applied when creating a new instance as opposed to retrieving an existing one) * @return an instance of the bean * @throws NoSuchBeanDefinitionException if there is no such bean definition * @throws BeanDefinitionStoreException if arguments have been given but diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java index b715484fe5..96f0d4fa71 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java @@ -487,8 +487,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac * factory method, and autowiring a constructor. * @param beanName the name of the bean * @param mbd the merged bean definition for the bean - * @param args arguments to use if creating a prototype using explicit arguments to a - * static factory method. This parameter must be {@code null} except in this case. + * @param args explicit arguments to use for constructor or factory method invocation * @return a new instance of the bean * @throws BeanCreationException if the bean could not be created * @see #instantiateBean @@ -988,8 +987,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac * factory method, constructor autowiring, or simple instantiation. * @param beanName the name of the bean * @param mbd the bean definition for the bean - * @param args arguments to use if creating a prototype using explicit arguments to a - * static factory method. It is invalid to use a non-null args value in any other case. + * @param args explicit arguments to use for constructor or factory method invocation * @return BeanWrapper for the new instance * @see #instantiateUsingFactoryMethod * @see #autowireConstructor 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 7802f04a1f..dc8d3ff5d4 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 @@ -207,8 +207,8 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp * Return an instance, which may be shared or independent, of the specified bean. * @param name the name of the bean to retrieve * @param requiredType the required type of the bean to retrieve - * @param args arguments to use if creating a prototype using explicit arguments to a - * static factory method. It is invalid to use a non-null args value in any other case. + * @param args arguments to use when creating a bean instance using explicit arguments + * (only applied when creating a new instance as opposed to retrieving an existing one) * @return an instance of the bean * @throws BeansException if the bean could not be created */ @@ -220,8 +220,8 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp * Return an instance, which may be shared or independent, of the specified bean. * @param name the name of the bean to retrieve * @param requiredType the required type of the bean to retrieve - * @param args arguments to use if creating a prototype using explicit arguments to a - * static factory method. It is invalid to use a non-null args value in any other case. + * @param args arguments to use when creating a bean instance using explicit arguments + * (only applied when creating a new instance as opposed to retrieving an existing one) * @param typeCheckOnly whether the instance is obtained for a type check, * not for actual use * @return an instance of the bean @@ -1266,17 +1266,9 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp protected void checkMergedBeanDefinition(RootBeanDefinition mbd, String beanName, Object[] args) throws BeanDefinitionStoreException { - // check if bean definition is not abstract if (mbd.isAbstract()) { throw new BeanIsAbstractException(beanName); } - - // Check validity of the usage of the args parameter. This can - // only be used for prototypes constructed via a factory method. - if (args != null && !mbd.isPrototype()) { - throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName, - "Can only specify arguments for the getBean method when referring to a prototype bean definition"); - } } /** @@ -1619,15 +1611,13 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException; /** - * Create a bean instance for the given bean definition. - * The bean definition will already have been merged with the parent - * definition in case of a child definition. - *

All the other methods in this class invoke this method, although - * beans may be cached after being instantiated by this method. All bean - * instantiation within this class is performed by this method. + * Create a bean instance for the given merged bean definition (and arguments). + * The bean definition will already have been merged with the parent definition + * in case of a child definition. + *

All bean retrieval methods delegate to this method for actual bean creation. * @param beanName the name of the bean * @param mbd the merged bean definition for the bean - * @param args arguments to use if creating a prototype using explicit arguments + * @param args explicit arguments to use for constructor or factory method invocation * @return a new instance of the bean * @throws BeanCreationException if the bean could not be created */ diff --git a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java index 0c1ccf2d7d..4b6d08df96 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java @@ -38,6 +38,7 @@ import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.support.ChildBeanDefinition; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.componentscan.simple.SimpleComponent; import org.springframework.core.env.StandardEnvironment; import org.springframework.core.io.DescriptiveResource; @@ -470,7 +471,13 @@ public class ConfigurationClassPostProcessorTests { @Test public void testPrototypeArgumentsThroughBeanMethodCall() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(BeanArgumentConfig.class); + ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanArgumentConfigWithPrototype.class); + ctx.getBean(FooFactory.class).createFoo(new BarArgument()); + } + + @Test + public void testSingletonArgumentsThroughBeanMethodCall() { + ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanArgumentConfigWithSingleton.class); ctx.getBean(FooFactory.class).createFoo(new BarArgument()); } @@ -932,7 +939,7 @@ public class ConfigurationClassPostProcessorTests { } @Configuration - static class BeanArgumentConfig { + static class BeanArgumentConfigWithPrototype { @Bean @Scope("prototype") @@ -951,6 +958,25 @@ public class ConfigurationClassPostProcessorTests { } } + @Configuration + static class BeanArgumentConfigWithSingleton { + + @Bean @Lazy + public DependingFoo foo(final BarArgument bar) { + return new DependingFoo(bar); + } + + @Bean + public FooFactory fooFactory() { + return new FooFactory() { + @Override + public DependingFoo createFoo(final BarArgument bar) { + return foo(bar); + } + }; + } + } + static class BarArgument { }