Support for functional instance supplier callback at BeanDefinition level
Issue: SPR-14832
This commit is contained in:
parent
12aa14ddbc
commit
3ee6286eb5
|
@ -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.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* 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();
|
||||
|
|
Loading…
Reference in New Issue