提交 3ee6286e 编写于 作者: J Juergen Hoeller

Support for functional instance supplier callback at BeanDefinition level

Issue: SPR-14832
上级 12aa14dd
......@@ -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);
}
......
......@@ -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.
* <p>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;
......
......@@ -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 <T> RootBeanDefinition(Class<T> beanClass, Supplier<T> instanceSupplier) {
super();
setBeanClass(beanClass);
setInstanceSupplier(instanceSupplier);
}
/**
* Create a new RootBeanDefinition for a scoped 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 scope the name of the corresponding scope
* @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 <T> RootBeanDefinition(Class<T> beanClass, String scope, Supplier<T> instanceSupplier) {
super();
setBeanClass(beanClass);
setScope(scope);
setInstanceSupplier(instanceSupplier);
}
/**
* Create a new RootBeanDefinition for a singleton,
* using the given autowire mode.
......
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -43,6 +43,7 @@ public class GenericApplicationContextTests {
ac.registerBeanDefinition("testBean", new RootBeanDefinition(String.class));
ac.refresh();
assertEquals("", ac.getBean("testBean"));
assertSame(ac.getBean("testBean"), ac.getBean(String.class));
assertSame(ac.getBean("testBean"), ac.getBean(CharSequence.class));
......@@ -55,6 +56,31 @@ public class GenericApplicationContextTests {
}
}
@Test
public void withSingletonSupplier() {
GenericApplicationContext ac = new GenericApplicationContext();
ac.registerBeanDefinition("testBean", new RootBeanDefinition(String.class, ac::toString));
ac.refresh();
assertSame(ac.getBean("testBean"), ac.getBean("testBean"));
assertSame(ac.getBean("testBean"), ac.getBean(String.class));
assertSame(ac.getBean("testBean"), ac.getBean(CharSequence.class));
assertEquals(ac.toString(), ac.getBean("testBean"));
}
@Test
public void withScopedSupplier() {
GenericApplicationContext ac = new GenericApplicationContext();
ac.registerBeanDefinition("testBean",
new RootBeanDefinition(String.class, RootBeanDefinition.SCOPE_PROTOTYPE, ac::toString));
ac.refresh();
assertNotSame(ac.getBean("testBean"), ac.getBean("testBean"));
assertEquals(ac.getBean("testBean"), ac.getBean(String.class));
assertEquals(ac.getBean("testBean"), ac.getBean(CharSequence.class));
assertEquals(ac.toString(), ac.getBean("testBean"));
}
@Test
public void accessAfterClosing() {
GenericApplicationContext ac = new GenericApplicationContext();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册