Pass pre-determined merged bean definition into InstanceSupplier (for inner beans)
Replaces useless protected obtainFromSupplier method with obtainInstanceFromSupplier. Moves InstanceSupplier handling to appropriate subclass (DefaultListableBeanFactory). BeanInstanceSupplier throws BeanInstantiationException instead of BeanCreationException. Closes gh-29803
This commit is contained in:
parent
6cd67412cc
commit
95710646d1
|
|
@ -27,9 +27,9 @@ import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.springframework.aot.hint.ExecutableMode;
|
import org.springframework.aot.hint.ExecutableMode;
|
||||||
|
import org.springframework.beans.BeanInstantiationException;
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.TypeConverter;
|
import org.springframework.beans.TypeConverter;
|
||||||
import org.springframework.beans.factory.BeanCreationException;
|
|
||||||
import org.springframework.beans.factory.BeanFactory;
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
import org.springframework.beans.factory.InjectionPoint;
|
import org.springframework.beans.factory.InjectionPoint;
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
|
|
@ -97,11 +97,13 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||||
private BeanInstanceSupplier(ExecutableLookup lookup,
|
private BeanInstanceSupplier(ExecutableLookup lookup,
|
||||||
@Nullable ThrowingBiFunction<RegisteredBean, AutowiredArguments, T> generator,
|
@Nullable ThrowingBiFunction<RegisteredBean, AutowiredArguments, T> generator,
|
||||||
@Nullable String[] shortcuts) {
|
@Nullable String[] shortcuts) {
|
||||||
|
|
||||||
this.lookup = lookup;
|
this.lookup = lookup;
|
||||||
this.generator = generator;
|
this.generator = generator;
|
||||||
this.shortcuts = shortcuts;
|
this.shortcuts = shortcuts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a {@link BeanInstanceSupplier} that resolves
|
* Create a {@link BeanInstanceSupplier} that resolves
|
||||||
* arguments for the specified bean constructor.
|
* arguments for the specified bean constructor.
|
||||||
|
|
@ -109,9 +111,7 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||||
* @param parameterTypes the constructor parameter types
|
* @param parameterTypes the constructor parameter types
|
||||||
* @return a new {@link BeanInstanceSupplier} instance
|
* @return a new {@link BeanInstanceSupplier} instance
|
||||||
*/
|
*/
|
||||||
public static <T> BeanInstanceSupplier<T> forConstructor(
|
public static <T> BeanInstanceSupplier<T> forConstructor(Class<?>... parameterTypes) {
|
||||||
Class<?>... parameterTypes) {
|
|
||||||
|
|
||||||
Assert.notNull(parameterTypes, "'parameterTypes' must not be null");
|
Assert.notNull(parameterTypes, "'parameterTypes' must not be null");
|
||||||
Assert.noNullElements(parameterTypes, "'parameterTypes' must not contain null elements");
|
Assert.noNullElements(parameterTypes, "'parameterTypes' must not contain null elements");
|
||||||
return new BeanInstanceSupplier<>(new ConstructorLookup(parameterTypes), null, null);
|
return new BeanInstanceSupplier<>(new ConstructorLookup(parameterTypes), null, null);
|
||||||
|
|
@ -149,11 +149,11 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||||
* @param generator a {@link ThrowingBiFunction} that uses the
|
* @param generator a {@link ThrowingBiFunction} that uses the
|
||||||
* {@link RegisteredBean} and resolved {@link AutowiredArguments} to
|
* {@link RegisteredBean} and resolved {@link AutowiredArguments} to
|
||||||
* instantiate the underlying bean
|
* instantiate the underlying bean
|
||||||
* @return a new {@link BeanInstanceSupplier} instance with the specified
|
* @return a new {@link BeanInstanceSupplier} instance with the specified generator
|
||||||
* generator
|
|
||||||
*/
|
*/
|
||||||
public BeanInstanceSupplier<T> withGenerator(
|
public BeanInstanceSupplier<T> withGenerator(
|
||||||
ThrowingBiFunction<RegisteredBean, AutowiredArguments, T> generator) {
|
ThrowingBiFunction<RegisteredBean, AutowiredArguments, T> generator) {
|
||||||
|
|
||||||
Assert.notNull(generator, "'generator' must not be null");
|
Assert.notNull(generator, "'generator' must not be null");
|
||||||
return new BeanInstanceSupplier<>(this.lookup, generator, this.shortcuts);
|
return new BeanInstanceSupplier<>(this.lookup, generator, this.shortcuts);
|
||||||
}
|
}
|
||||||
|
|
@ -163,11 +163,9 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||||
* {@code generator} function to instantiate the underlying bean.
|
* {@code generator} function to instantiate the underlying bean.
|
||||||
* @param generator a {@link ThrowingFunction} that uses the
|
* @param generator a {@link ThrowingFunction} that uses the
|
||||||
* {@link RegisteredBean} to instantiate the underlying bean
|
* {@link RegisteredBean} to instantiate the underlying bean
|
||||||
* @return a new {@link BeanInstanceSupplier} instance with the specified
|
* @return a new {@link BeanInstanceSupplier} instance with the specified generator
|
||||||
* generator
|
|
||||||
*/
|
*/
|
||||||
public BeanInstanceSupplier<T> withGenerator(
|
public BeanInstanceSupplier<T> withGenerator(ThrowingFunction<RegisteredBean, T> generator) {
|
||||||
ThrowingFunction<RegisteredBean, T> generator) {
|
|
||||||
Assert.notNull(generator, "'generator' must not be null");
|
Assert.notNull(generator, "'generator' must not be null");
|
||||||
return new BeanInstanceSupplier<>(this.lookup,
|
return new BeanInstanceSupplier<>(this.lookup,
|
||||||
(registeredBean, args) -> generator.apply(registeredBean), this.shortcuts);
|
(registeredBean, args) -> generator.apply(registeredBean), this.shortcuts);
|
||||||
|
|
@ -176,10 +174,8 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||||
/**
|
/**
|
||||||
* Return a new {@link BeanInstanceSupplier} instance that uses the specified
|
* Return a new {@link BeanInstanceSupplier} instance that uses the specified
|
||||||
* {@code generator} supplier to instantiate the underlying bean.
|
* {@code generator} supplier to instantiate the underlying bean.
|
||||||
* @param generator a {@link ThrowingSupplier} to instantiate the underlying
|
* @param generator a {@link ThrowingSupplier} to instantiate the underlying bean
|
||||||
* bean
|
* @return a new {@link BeanInstanceSupplier} instance with the specified generator
|
||||||
* @return a new {@link BeanInstanceSupplier} instance with the specified
|
|
||||||
* generator
|
|
||||||
*/
|
*/
|
||||||
public BeanInstanceSupplier<T> withGenerator(ThrowingSupplier<T> generator) {
|
public BeanInstanceSupplier<T> withGenerator(ThrowingSupplier<T> generator) {
|
||||||
Assert.notNull(generator, "'generator' must not be null");
|
Assert.notNull(generator, "'generator' must not be null");
|
||||||
|
|
@ -282,8 +278,7 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||||
if (executable instanceof Method method) {
|
if (executable instanceof Method method) {
|
||||||
return new MethodParameter(method, index);
|
return new MethodParameter(method, index);
|
||||||
}
|
}
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException("Unsupported executable: " + executable.getClass().getName());
|
||||||
"Unsupported executable " + executable.getClass().getName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConstructorArgumentValues resolveArgumentValues(
|
private ConstructorArgumentValues resolveArgumentValues(
|
||||||
|
|
@ -303,9 +298,7 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||||
return resolved;
|
return resolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ValueHolder resolveArgumentValue(BeanDefinitionValueResolver resolver,
|
private ValueHolder resolveArgumentValue(BeanDefinitionValueResolver resolver, ValueHolder valueHolder) {
|
||||||
ValueHolder valueHolder) {
|
|
||||||
|
|
||||||
if (valueHolder.isConverted()) {
|
if (valueHolder.isConverted()) {
|
||||||
return valueHolder;
|
return valueHolder;
|
||||||
}
|
}
|
||||||
|
|
@ -331,8 +324,7 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
return beanFactory.resolveDependency(dependencyDescriptor, beanName,
|
return beanFactory.resolveDependency(dependencyDescriptor, beanName, autowiredBeans, typeConverter);
|
||||||
autowiredBeans, typeConverter);
|
|
||||||
}
|
}
|
||||||
catch (NoSuchBeanDefinitionException ex) {
|
catch (NoSuchBeanDefinitionException ex) {
|
||||||
if (parameterType.isArray()) {
|
if (parameterType.isArray()) {
|
||||||
|
|
@ -348,47 +340,45 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (BeansException ex) {
|
catch (BeansException ex) {
|
||||||
throw new UnsatisfiedDependencyException(null, beanName,
|
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(parameter), ex);
|
||||||
new InjectionPoint(parameter), ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private T instantiate(ConfigurableBeanFactory beanFactory, Executable executable,
|
private T instantiate(ConfigurableBeanFactory beanFactory, Executable executable, Object[] args) {
|
||||||
Object[] arguments) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (executable instanceof Constructor<?> constructor) {
|
if (executable instanceof Constructor<?> constructor) {
|
||||||
return (T) instantiate(constructor, arguments);
|
try {
|
||||||
}
|
return (T) instantiate(constructor, args);
|
||||||
if (executable instanceof Method method) {
|
|
||||||
return (T) instantiate(beanFactory, method, arguments);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
throw new BeanCreationException(
|
throw new BeanInstantiationException(constructor, ex.getMessage(), ex);
|
||||||
"Unable to instantiate bean using " + executable, ex);
|
|
||||||
}
|
}
|
||||||
throw new IllegalStateException(
|
}
|
||||||
"Unsupported executable " + executable.getClass().getName());
|
if (executable instanceof Method method) {
|
||||||
|
try {
|
||||||
|
return (T) instantiate(beanFactory, method, args);
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
throw new BeanInstantiationException(method, ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Unsupported executable " + executable.getClass().getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object instantiate(Constructor<?> constructor, Object[] arguments) throws Exception {
|
private Object instantiate(Constructor<?> constructor, Object[] args) throws Exception {
|
||||||
Class<?> declaringClass = constructor.getDeclaringClass();
|
Class<?> declaringClass = constructor.getDeclaringClass();
|
||||||
if (ClassUtils.isInnerClass(declaringClass)) {
|
if (ClassUtils.isInnerClass(declaringClass)) {
|
||||||
Object enclosingInstance = createInstance(declaringClass.getEnclosingClass());
|
Object enclosingInstance = createInstance(declaringClass.getEnclosingClass());
|
||||||
arguments = ObjectUtils.addObjectToArray(arguments, enclosingInstance, 0);
|
args = ObjectUtils.addObjectToArray(args, enclosingInstance, 0);
|
||||||
}
|
}
|
||||||
ReflectionUtils.makeAccessible(constructor);
|
ReflectionUtils.makeAccessible(constructor);
|
||||||
return constructor.newInstance(arguments);
|
return constructor.newInstance(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object instantiate(ConfigurableBeanFactory beanFactory, Method method,
|
private Object instantiate(ConfigurableBeanFactory beanFactory, Method method, Object[] args) throws Exception {
|
||||||
Object[] arguments) {
|
|
||||||
|
|
||||||
ReflectionUtils.makeAccessible(method);
|
|
||||||
Object target = getFactoryMethodTarget(beanFactory, method);
|
Object target = getFactoryMethodTarget(beanFactory, method);
|
||||||
return ReflectionUtils.invokeMethod(method, target, arguments);
|
ReflectionUtils.makeAccessible(method);
|
||||||
|
return method.invoke(target, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|
@ -416,13 +406,13 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||||
return Arrays.stream(parameterTypes).map(Class::getName).collect(Collectors.joining(", "));
|
return Arrays.stream(parameterTypes).map(Class::getName).collect(Collectors.joining(", "));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs lookup of the {@link Executable}.
|
* Performs lookup of the {@link Executable}.
|
||||||
*/
|
*/
|
||||||
static abstract class ExecutableLookup {
|
static abstract class ExecutableLookup {
|
||||||
|
|
||||||
abstract Executable get(RegisteredBean registeredBean);
|
abstract Executable get(RegisteredBean registeredBean);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -433,12 +423,10 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||||
|
|
||||||
private final Class<?>[] parameterTypes;
|
private final Class<?>[] parameterTypes;
|
||||||
|
|
||||||
|
|
||||||
ConstructorLookup(Class<?>[] parameterTypes) {
|
ConstructorLookup(Class<?>[] parameterTypes) {
|
||||||
this.parameterTypes = parameterTypes;
|
this.parameterTypes = parameterTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Executable get(RegisteredBean registeredBean) {
|
public Executable get(RegisteredBean registeredBean) {
|
||||||
Class<?> beanClass = registeredBean.getBeanClass();
|
Class<?> beanClass = registeredBean.getBeanClass();
|
||||||
|
|
@ -456,10 +444,8 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Constructor with parameter types [%s]".formatted(
|
return "Constructor with parameter types [%s]".formatted(toCommaSeparatedNames(this.parameterTypes));
|
||||||
toCommaSeparatedNames(this.parameterTypes));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -474,23 +460,19 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||||
|
|
||||||
private final Class<?>[] parameterTypes;
|
private final Class<?>[] parameterTypes;
|
||||||
|
|
||||||
|
FactoryMethodLookup(Class<?> declaringClass, String methodName, Class<?>[] parameterTypes) {
|
||||||
FactoryMethodLookup(Class<?> declaringClass, String methodName,
|
|
||||||
Class<?>[] parameterTypes) {
|
|
||||||
this.declaringClass = declaringClass;
|
this.declaringClass = declaringClass;
|
||||||
this.methodName = methodName;
|
this.methodName = methodName;
|
||||||
this.parameterTypes = parameterTypes;
|
this.parameterTypes = parameterTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Executable get(RegisteredBean registeredBean) {
|
public Executable get(RegisteredBean registeredBean) {
|
||||||
return get();
|
return get();
|
||||||
}
|
}
|
||||||
|
|
||||||
Method get() {
|
Method get() {
|
||||||
Method method = ReflectionUtils.findMethod(this.declaringClass,
|
Method method = ReflectionUtils.findMethod(this.declaringClass, this.methodName, this.parameterTypes);
|
||||||
this.methodName, this.parameterTypes);
|
|
||||||
Assert.notNull(method, () -> "%s cannot be found".formatted(this));
|
Assert.notNull(method, () -> "%s cannot be found".formatted(this));
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
|
|
@ -501,7 +483,6 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||||
this.methodName, toCommaSeparatedNames(this.parameterTypes),
|
this.methodName, toCommaSeparatedNames(this.parameterTypes),
|
||||||
this.declaringClass);
|
this.declaringClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,6 @@ import org.springframework.beans.factory.config.AutowiredPropertyMarker;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
|
||||||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||||
import org.springframework.beans.factory.config.DependencyDescriptor;
|
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||||
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
|
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
|
||||||
|
|
@ -1154,7 +1153,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||||
|
|
||||||
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
|
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
|
||||||
if (instanceSupplier != null) {
|
if (instanceSupplier != null) {
|
||||||
return obtainFromSupplier(instanceSupplier, beanName);
|
return obtainFromSupplier(instanceSupplier, beanName, mbd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mbd.getFactoryMethodName() != null) {
|
if (mbd.getFactoryMethodName() != null) {
|
||||||
|
|
@ -1203,38 +1202,20 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||||
* @param supplier the configured supplier
|
* @param supplier the configured supplier
|
||||||
* @param beanName the corresponding bean name
|
* @param beanName the corresponding bean name
|
||||||
* @return a BeanWrapper for the new instance
|
* @return a BeanWrapper for the new instance
|
||||||
* @since 5.0
|
|
||||||
* @see #getObjectForBeanInstance
|
|
||||||
*/
|
*/
|
||||||
protected BeanWrapper obtainFromSupplier(Supplier<?> supplier, String beanName) {
|
private BeanWrapper obtainFromSupplier(Supplier<?> supplier, String beanName, RootBeanDefinition mbd) {
|
||||||
Object instance = obtainInstanceFromSupplier(supplier, beanName);
|
|
||||||
if (instance == null) {
|
|
||||||
instance = new NullBean();
|
|
||||||
}
|
|
||||||
BeanWrapper bw = new BeanWrapperImpl(instance);
|
|
||||||
initBeanWrapper(bw);
|
|
||||||
return bw;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private Object obtainInstanceFromSupplier(Supplier<?> supplier, String beanName) {
|
|
||||||
String outerBean = this.currentlyCreatedBean.get();
|
String outerBean = this.currentlyCreatedBean.get();
|
||||||
this.currentlyCreatedBean.set(beanName);
|
this.currentlyCreatedBean.set(beanName);
|
||||||
|
Object instance;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (supplier instanceof InstanceSupplier<?> instanceSupplier) {
|
instance = obtainInstanceFromSupplier(supplier, beanName, mbd);
|
||||||
return instanceSupplier.get(RegisteredBean.of((ConfigurableListableBeanFactory) this, beanName));
|
|
||||||
}
|
|
||||||
if (supplier instanceof ThrowingSupplier<?> throwingSupplier) {
|
|
||||||
return throwingSupplier.getWithException();
|
|
||||||
}
|
|
||||||
return supplier.get();
|
|
||||||
}
|
}
|
||||||
catch (Throwable ex) {
|
catch (Throwable ex) {
|
||||||
if (ex instanceof BeansException beansException) {
|
if (ex instanceof BeansException beansException) {
|
||||||
throw beansException;
|
throw beansException;
|
||||||
}
|
}
|
||||||
throw new BeanCreationException(beanName,
|
throw new BeanCreationException(beanName, "Instantiation of supplied bean failed", ex);
|
||||||
"Instantiation of supplied bean failed", ex);
|
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
if (outerBean != null) {
|
if (outerBean != null) {
|
||||||
|
|
@ -1244,6 +1225,31 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||||
this.currentlyCreatedBean.remove();
|
this.currentlyCreatedBean.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new NullBean();
|
||||||
|
}
|
||||||
|
BeanWrapper bw = new BeanWrapperImpl(instance);
|
||||||
|
initBeanWrapper(bw);
|
||||||
|
return bw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain a bean instance from the given supplier.
|
||||||
|
* @param supplier the configured supplier
|
||||||
|
* @param beanName the corresponding bean name
|
||||||
|
* @param mbd the bean definition for the bean
|
||||||
|
* @return the bean instance (possibly {@code null})
|
||||||
|
* @since 6.0.7
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
protected Object obtainInstanceFromSupplier(Supplier<?> supplier, String beanName, RootBeanDefinition mbd)
|
||||||
|
throws Exception {
|
||||||
|
|
||||||
|
if (supplier instanceof ThrowingSupplier<?> throwingSupplier) {
|
||||||
|
return throwingSupplier.getWithException();
|
||||||
|
}
|
||||||
|
return supplier.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2022 the original author or authors.
|
* Copyright 2002-2023 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -40,6 +40,7 @@ import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import jakarta.inject.Provider;
|
import jakarta.inject.Provider;
|
||||||
|
|
@ -937,6 +938,17 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
return (this.configurationFrozen || super.isBeanEligibleForMetadataCaching(beanName));
|
return (this.configurationFrozen || super.isBeanEligibleForMetadataCaching(beanName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
protected Object obtainInstanceFromSupplier(Supplier<?> supplier, String beanName, RootBeanDefinition mbd)
|
||||||
|
throws Exception {
|
||||||
|
|
||||||
|
if (supplier instanceof InstanceSupplier<?> instanceSupplier) {
|
||||||
|
return instanceSupplier.get(RegisteredBean.of(this, beanName, mbd));
|
||||||
|
}
|
||||||
|
return super.obtainInstanceFromSupplier(supplier, beanName, mbd);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void preInstantiateSingletons() throws BeansException {
|
public void preInstantiateSingletons() throws BeansException {
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2022 the original author or authors.
|
* Copyright 2002-2023 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -35,6 +35,7 @@ import org.springframework.util.function.ThrowingSupplier;
|
||||||
* @since 6.0
|
* @since 6.0
|
||||||
* @param <T> the type of instance supplied by this supplier
|
* @param <T> the type of instance supplied by this supplier
|
||||||
* @see RegisteredBean
|
* @see RegisteredBean
|
||||||
|
* @see org.springframework.beans.factory.aot.BeanInstanceSupplier
|
||||||
*/
|
*/
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface InstanceSupplier<T> extends ThrowingSupplier<T> {
|
public interface InstanceSupplier<T> extends ThrowingSupplier<T> {
|
||||||
|
|
@ -74,19 +75,17 @@ public interface InstanceSupplier<T> extends ThrowingSupplier<T> {
|
||||||
*/
|
*/
|
||||||
default <V> InstanceSupplier<V> andThen(
|
default <V> InstanceSupplier<V> andThen(
|
||||||
ThrowingBiFunction<RegisteredBean, ? super T, ? extends V> after) {
|
ThrowingBiFunction<RegisteredBean, ? super T, ? extends V> after) {
|
||||||
|
|
||||||
Assert.notNull(after, "'after' function must not be null");
|
Assert.notNull(after, "'after' function must not be null");
|
||||||
return new InstanceSupplier<>() {
|
return new InstanceSupplier<>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public V get(RegisteredBean registeredBean) throws Exception {
|
public V get(RegisteredBean registeredBean) throws Exception {
|
||||||
return after.applyWithException(registeredBean, InstanceSupplier.this.get(registeredBean));
|
return after.applyWithException(registeredBean, InstanceSupplier.this.get(registeredBean));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Method getFactoryMethod() {
|
public Method getFactoryMethod() {
|
||||||
return InstanceSupplier.this.getFactoryMethod();
|
return InstanceSupplier.this.getFactoryMethod();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,22 +114,21 @@ public interface InstanceSupplier<T> extends ThrowingSupplier<T> {
|
||||||
*/
|
*/
|
||||||
static <T> InstanceSupplier<T> using(@Nullable Method factoryMethod, ThrowingSupplier<T> supplier) {
|
static <T> InstanceSupplier<T> using(@Nullable Method factoryMethod, ThrowingSupplier<T> supplier) {
|
||||||
Assert.notNull(supplier, "Supplier must not be null");
|
Assert.notNull(supplier, "Supplier must not be null");
|
||||||
if (supplier instanceof InstanceSupplier<T> instanceSupplier
|
|
||||||
&& instanceSupplier.getFactoryMethod() == factoryMethod) {
|
if (supplier instanceof InstanceSupplier<T> instanceSupplier &&
|
||||||
|
instanceSupplier.getFactoryMethod() == factoryMethod) {
|
||||||
return instanceSupplier;
|
return instanceSupplier;
|
||||||
}
|
}
|
||||||
return new InstanceSupplier<>() {
|
|
||||||
|
|
||||||
|
return new InstanceSupplier<>() {
|
||||||
@Override
|
@Override
|
||||||
public T get(RegisteredBean registeredBean) throws Exception {
|
public T get(RegisteredBean registeredBean) throws Exception {
|
||||||
return supplier.getWithException();
|
return supplier.getWithException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Method getFactoryMethod() {
|
public Method getFactoryMethod() {
|
||||||
return factoryMethod;
|
return factoryMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2022 the original author or authors.
|
* Copyright 2002-2023 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -80,6 +80,18 @@ public final class RegisteredBean {
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link RegisteredBean} instance for a regular bean.
|
||||||
|
* @param beanFactory the source bean factory
|
||||||
|
* @param beanName the bean name
|
||||||
|
* @param mbd the pre-determined merged bean definition
|
||||||
|
* @return a new {@link RegisteredBean} instance
|
||||||
|
* @since 6.0.7
|
||||||
|
*/
|
||||||
|
static RegisteredBean of(ConfigurableListableBeanFactory beanFactory, String beanName, RootBeanDefinition mbd) {
|
||||||
|
return new RegisteredBean(beanFactory, () -> beanName, false, () -> mbd, null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link RegisteredBean} instance for an inner-bean.
|
* Create a new {@link RegisteredBean} instance for an inner-bean.
|
||||||
* @param parent the parent of the inner-bean
|
* @param parent the parent of the inner-bean
|
||||||
|
|
@ -220,45 +232,34 @@ public final class RegisteredBean {
|
||||||
@Nullable
|
@Nullable
|
||||||
private volatile String resolvedBeanName;
|
private volatile String resolvedBeanName;
|
||||||
|
|
||||||
|
InnerBeanResolver(RegisteredBean parent, @Nullable String innerBeanName, BeanDefinition innerBeanDefinition) {
|
||||||
InnerBeanResolver(RegisteredBean parent, @Nullable String innerBeanName,
|
Assert.isInstanceOf(AbstractAutowireCapableBeanFactory.class, parent.getBeanFactory());
|
||||||
BeanDefinition innerBeanDefinition) {
|
|
||||||
|
|
||||||
Assert.isInstanceOf(AbstractAutowireCapableBeanFactory.class,
|
|
||||||
parent.getBeanFactory());
|
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.innerBeanName = innerBeanName;
|
this.innerBeanName = innerBeanName;
|
||||||
this.innerBeanDefinition = innerBeanDefinition;
|
this.innerBeanDefinition = innerBeanDefinition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
String resolveBeanName() {
|
String resolveBeanName() {
|
||||||
String resolvedBeanName = this.resolvedBeanName;
|
String resolvedBeanName = this.resolvedBeanName;
|
||||||
if (resolvedBeanName != null) {
|
if (resolvedBeanName != null) {
|
||||||
return resolvedBeanName;
|
return resolvedBeanName;
|
||||||
}
|
}
|
||||||
resolvedBeanName = resolveInnerBean(
|
resolvedBeanName = resolveInnerBean((beanName, mergedBeanDefinition) -> beanName);
|
||||||
(beanName, mergedBeanDefinition) -> beanName);
|
|
||||||
this.resolvedBeanName = resolvedBeanName;
|
this.resolvedBeanName = resolvedBeanName;
|
||||||
return resolvedBeanName;
|
return resolvedBeanName;
|
||||||
}
|
}
|
||||||
|
|
||||||
RootBeanDefinition resolveMergedBeanDefinition() {
|
RootBeanDefinition resolveMergedBeanDefinition() {
|
||||||
return resolveInnerBean(
|
return resolveInnerBean((beanName, mergedBeanDefinition) -> mergedBeanDefinition);
|
||||||
(beanName, mergedBeanDefinition) -> mergedBeanDefinition);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> T resolveInnerBean(
|
private <T> T resolveInnerBean(BiFunction<String, RootBeanDefinition, T> resolver) {
|
||||||
BiFunction<String, RootBeanDefinition, T> resolver) {
|
|
||||||
|
|
||||||
// Always use a fresh BeanDefinitionValueResolver in case the parent merged bean definition has changed.
|
// Always use a fresh BeanDefinitionValueResolver in case the parent merged bean definition has changed.
|
||||||
BeanDefinitionValueResolver beanDefinitionValueResolver = new BeanDefinitionValueResolver(
|
BeanDefinitionValueResolver beanDefinitionValueResolver = new BeanDefinitionValueResolver(
|
||||||
(AbstractAutowireCapableBeanFactory) this.parent.getBeanFactory(),
|
(AbstractAutowireCapableBeanFactory) this.parent.getBeanFactory(),
|
||||||
this.parent.getBeanName(), this.parent.getMergedBeanDefinition());
|
this.parent.getBeanName(), this.parent.getMergedBeanDefinition());
|
||||||
return beanDefinitionValueResolver.resolveInnerBean(this.innerBeanName,
|
return beanDefinitionValueResolver.resolveInnerBean(this.innerBeanName, this.innerBeanDefinition, resolver);
|
||||||
this.innerBeanDefinition, resolver);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2022 the original author or authors.
|
* Copyright 2002-2023 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -27,10 +27,10 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link AbstractAutowireCapableBeanFactory} instance supplier
|
* Tests for {@link AbstractAutowireCapableBeanFactory} instance supplier support.
|
||||||
* support.
|
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Juergen Hoeller
|
||||||
*/
|
*/
|
||||||
public class BeanFactorySupplierTests {
|
public class BeanFactorySupplierTests {
|
||||||
|
|
||||||
|
|
@ -44,13 +44,38 @@ public class BeanFactorySupplierTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void getBeanWhenUsingInstanceSupplier() {
|
void getBeanWithInnerBeanUsingRegularSupplier() {
|
||||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||||
RootBeanDefinition beanDefinition = new RootBeanDefinition();
|
RootBeanDefinition beanDefinition = new RootBeanDefinition();
|
||||||
beanDefinition.setInstanceSupplier(InstanceSupplier
|
beanDefinition.setInstanceSupplier(() -> "I am supplied");
|
||||||
.of(registeredBean -> "I am bean " + registeredBean.getBeanName()));
|
RootBeanDefinition outerBean = new RootBeanDefinition(String.class);
|
||||||
|
outerBean.getConstructorArgumentValues().addGenericArgumentValue(beanDefinition);
|
||||||
|
beanFactory.registerBeanDefinition("test", outerBean);
|
||||||
|
assertThat(beanFactory.getBean("test")).asString().startsWith("I am supplied");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getBeanWhenUsingInstanceSupplier() {
|
||||||
|
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||||
|
RootBeanDefinition beanDefinition = new RootBeanDefinition(String.class);
|
||||||
|
beanDefinition.setInstanceSupplier(InstanceSupplier.of(registeredBean ->
|
||||||
|
"I am bean " + registeredBean.getBeanName() + " of " + registeredBean.getBeanClass()));
|
||||||
beanFactory.registerBeanDefinition("test", beanDefinition);
|
beanFactory.registerBeanDefinition("test", beanDefinition);
|
||||||
assertThat(beanFactory.getBean("test")).isEqualTo("I am bean test");
|
assertThat(beanFactory.getBean("test")).isEqualTo("I am bean test of class java.lang.String");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getBeanWithInnerBeanUsingInstanceSupplier() {
|
||||||
|
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||||
|
RootBeanDefinition beanDefinition = new RootBeanDefinition(String.class);
|
||||||
|
beanDefinition.setInstanceSupplier(InstanceSupplier.of(registeredBean ->
|
||||||
|
"I am bean " + registeredBean.getBeanName() + " of " + registeredBean.getBeanClass()));
|
||||||
|
RootBeanDefinition outerBean = new RootBeanDefinition(String.class);
|
||||||
|
outerBean.getConstructorArgumentValues().addGenericArgumentValue(beanDefinition);
|
||||||
|
beanFactory.registerBeanDefinition("test", outerBean);
|
||||||
|
assertThat(beanFactory.getBean("test")).asString()
|
||||||
|
.startsWith("I am bean (inner bean)")
|
||||||
|
.endsWith(" of class java.lang.String");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -62,6 +87,17 @@ public class BeanFactorySupplierTests {
|
||||||
assertThat(beanFactory.getBean("test")).isEqualTo("I am supplied");
|
assertThat(beanFactory.getBean("test")).isEqualTo("I am supplied");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getBeanWithInnerBeanUsingThrowableSupplier() {
|
||||||
|
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||||
|
RootBeanDefinition beanDefinition = new RootBeanDefinition();
|
||||||
|
beanDefinition.setInstanceSupplier(ThrowingSupplier.of(() -> "I am supplied"));
|
||||||
|
RootBeanDefinition outerBean = new RootBeanDefinition(String.class);
|
||||||
|
outerBean.getConstructorArgumentValues().addGenericArgumentValue(beanDefinition);
|
||||||
|
beanFactory.registerBeanDefinition("test", outerBean);
|
||||||
|
assertThat(beanFactory.getBean("test")).asString().startsWith("I am supplied");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void getBeanWhenUsingThrowableSupplierThatThrowsCheckedException() {
|
void getBeanWhenUsingThrowableSupplierThatThrowsCheckedException() {
|
||||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue