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 c3c7183c75..dadb3fba83 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 @@ -38,6 +38,7 @@ import java.util.Set; import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.function.Supplier; import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanWrapper; @@ -1036,6 +1037,13 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac "Bean class isn't public, and non-public access not allowed: " + beanClass.getName()); } + Supplier> instanceSupplier = mbd.getInstanceSupplier(); + if (instanceSupplier != null) { + BeanWrapper bw = new BeanWrapperImpl(instanceSupplier.get()); + initBeanWrapper(bw); + return bw; + } + if (mbd.getFactoryMethodName() != null) { return instantiateUsingFactoryMethod(beanName, mbd, args); } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java index 7b2e264787..9c42e31b14 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanDefinition.java @@ -22,6 +22,7 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; +import java.util.function.Supplier; import org.springframework.beans.BeanMetadataAttributeAccessor; import org.springframework.beans.MutablePropertyValues; @@ -165,6 +166,8 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess private MethodOverrides methodOverrides = new MethodOverrides(); + private Supplier> instanceSupplier; + private String factoryBeanName; private String factoryMethodName; @@ -234,6 +237,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess setPrimary(originalAbd.isPrimary()); setNonPublicAccessAllowed(originalAbd.isNonPublicAccessAllowed()); setLenientConstructorResolution(originalAbd.isLenientConstructorResolution()); + setInstanceSupplier(originalAbd.getInstanceSupplier()); setInitMethodName(originalAbd.getInitMethodName()); setEnforceInitMethod(originalAbd.isEnforceInitMethod()); setDestroyMethodName(originalAbd.getDestroyMethodName()); @@ -298,6 +302,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess setDependsOn(otherAbd.getDependsOn()); setNonPublicAccessAllowed(otherAbd.isNonPublicAccessAllowed()); setLenientConstructorResolution(otherAbd.isLenientConstructorResolution()); + setInstanceSupplier(otherAbd.getInstanceSupplier()); if (StringUtils.hasLength(otherAbd.getInitMethodName())) { setInitMethodName(otherAbd.getInitMethodName()); setEnforceInitMethod(otherAbd.isEnforceInitMethod()); @@ -738,6 +743,28 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess } + /** + * Specify a callback for creating an instance of the bean, + * as an alternative to a declaratively specified factory method. + *
If such a callback is set, it will override any other constructor
+ * or factory method metadata. However, bean property population and
+ * potential annotation-driven injection will still apply as usual.
+ * @since 5.0
+ * @see #setConstructorArgumentValues(ConstructorArgumentValues)
+ * @see #setPropertyValues(MutablePropertyValues)
+ */
+ public void setInstanceSupplier(Supplier> instanceSupplier) {
+ this.instanceSupplier = instanceSupplier;
+ }
+
+ /**
+ * Return a callback for creating an instance of the bean, if any.
+ * @since 5.0
+ */
+ public Supplier> getInstanceSupplier() {
+ return this.instanceSupplier;
+ }
+
@Override
public void setFactoryBeanName(String factoryBeanName) {
this.factoryBeanName = factoryBeanName;
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java
index f04ea65166..64908bd340 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java
@@ -22,6 +22,7 @@ import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
+import java.util.function.Supplier;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -116,12 +117,45 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
/**
* Create a new RootBeanDefinition for a singleton.
* @param beanClass the class of the bean to instantiate
+ * @see #setBeanClass
*/
public RootBeanDefinition(Class> beanClass) {
super();
setBeanClass(beanClass);
}
+ /**
+ * Create a new RootBeanDefinition for a singleton bean, constructing each instance
+ * through calling the given supplier (possibly a lambda or method reference).
+ * @param beanClass the class of the bean to instantiate
+ * @param instanceSupplier the supplier to construct a bean instance,
+ * as an alternative to a declaratively specified factory method
+ * @since 5.0
+ * @see #setInstanceSupplier(Supplier)
+ */
+ public