Provide a template method to expose the currently invoked factory method
This commit improves SimpleInstantiationStrategy by providing a common template method before the regular runtime and AOT. As a result, the method to set the currently invoked factory method is deprecated as it should no longer be used. Closes gh-33192
This commit is contained in:
parent
0c319a89d7
commit
6de624d537
|
@ -213,14 +213,7 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
||||||
if (!(executable instanceof Method method)) {
|
if (!(executable instanceof Method method)) {
|
||||||
return beanSupplier.get();
|
return beanSupplier.get();
|
||||||
}
|
}
|
||||||
Method priorInvokedFactoryMethod = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
|
return SimpleInstantiationStrategy.instantiateWithFactoryMethod(method, beanSupplier::get);
|
||||||
try {
|
|
||||||
SimpleInstantiationStrategy.setCurrentlyInvokedFactoryMethod(method);
|
|
||||||
return beanSupplier.get();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
SimpleInstantiationStrategy.setCurrentlyInvokedFactoryMethod(priorInvokedFactoryMethod);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|
|
@ -27,6 +27,7 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.util.function.ThrowingSupplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple object instantiation strategy for use in a BeanFactory.
|
* Simple object instantiation strategy for use in a BeanFactory.
|
||||||
|
@ -59,7 +60,9 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
|
||||||
* the current value, if any.
|
* the current value, if any.
|
||||||
* @param method the factory method currently being invoked or {@code null}
|
* @param method the factory method currently being invoked or {@code null}
|
||||||
* @since 6.0
|
* @since 6.0
|
||||||
|
* @deprecated in favor of {@link #instantiateWithFactoryMethod(Method, ThrowingSupplier)}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(since = "6.2", forRemoval = true)
|
||||||
public static void setCurrentlyInvokedFactoryMethod(@Nullable Method method) {
|
public static void setCurrentlyInvokedFactoryMethod(@Nullable Method method) {
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
currentlyInvokedFactoryMethod.set(method);
|
currentlyInvokedFactoryMethod.set(method);
|
||||||
|
@ -69,6 +72,31 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoke the given {@code instanceSupplier} with the factory method exposed
|
||||||
|
* as being invoked.
|
||||||
|
* @param method the factory method to expose
|
||||||
|
* @param instanceSupplier the instance supplier
|
||||||
|
* @param <T> the type of the instance
|
||||||
|
* @return the result of the instance supplier
|
||||||
|
* @since 6.2
|
||||||
|
*/
|
||||||
|
public static <T> T instantiateWithFactoryMethod(Method method, ThrowingSupplier<T> instanceSupplier) {
|
||||||
|
Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
|
||||||
|
try {
|
||||||
|
currentlyInvokedFactoryMethod.set(method);
|
||||||
|
return instanceSupplier.get();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if (priorInvokedFactoryMethod != null) {
|
||||||
|
currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
currentlyInvokedFactoryMethod.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
|
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
|
||||||
|
@ -137,46 +165,40 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
|
||||||
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
|
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
|
||||||
@Nullable Object factoryBean, Method factoryMethod, Object... args) {
|
@Nullable Object factoryBean, Method factoryMethod, Object... args) {
|
||||||
|
|
||||||
try {
|
return instantiateWithFactoryMethod(factoryMethod, () -> {
|
||||||
ReflectionUtils.makeAccessible(factoryMethod);
|
|
||||||
|
|
||||||
Method priorInvokedFactoryMethod = getCurrentlyInvokedFactoryMethod();
|
|
||||||
try {
|
try {
|
||||||
setCurrentlyInvokedFactoryMethod(factoryMethod);
|
ReflectionUtils.makeAccessible(factoryMethod);
|
||||||
Object result = factoryMethod.invoke(factoryBean, args);
|
Object result = factoryMethod.invoke(factoryBean, args);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
result = new NullBean();
|
result = new NullBean();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
finally {
|
catch (IllegalArgumentException ex) {
|
||||||
setCurrentlyInvokedFactoryMethod(priorInvokedFactoryMethod);
|
if (factoryBean != null && !factoryMethod.getDeclaringClass().isAssignableFrom(factoryBean.getClass())) {
|
||||||
}
|
throw new BeanInstantiationException(factoryMethod,
|
||||||
}
|
"Illegal factory instance for factory method '" + factoryMethod.getName() + "'; " +
|
||||||
catch (IllegalArgumentException ex) {
|
"instance: " + factoryBean.getClass().getName(), ex);
|
||||||
if (factoryBean != null && !factoryMethod.getDeclaringClass().isAssignableFrom(factoryBean.getClass())) {
|
}
|
||||||
throw new BeanInstantiationException(factoryMethod,
|
throw new BeanInstantiationException(factoryMethod,
|
||||||
"Illegal factory instance for factory method '" + factoryMethod.getName() + "'; " +
|
"Illegal arguments to factory method '" + factoryMethod.getName() + "'; " +
|
||||||
"instance: " + factoryBean.getClass().getName(), ex);
|
"args: " + StringUtils.arrayToCommaDelimitedString(args), ex);
|
||||||
}
|
}
|
||||||
throw new BeanInstantiationException(factoryMethod,
|
catch (IllegalAccessException ex) {
|
||||||
"Illegal arguments to factory method '" + factoryMethod.getName() + "'; " +
|
throw new BeanInstantiationException(factoryMethod,
|
||||||
"args: " + StringUtils.arrayToCommaDelimitedString(args), ex);
|
"Cannot access factory method '" + factoryMethod.getName() + "'; is it public?", ex);
|
||||||
}
|
|
||||||
catch (IllegalAccessException ex) {
|
|
||||||
throw new BeanInstantiationException(factoryMethod,
|
|
||||||
"Cannot access factory method '" + factoryMethod.getName() + "'; is it public?", ex);
|
|
||||||
}
|
|
||||||
catch (InvocationTargetException ex) {
|
|
||||||
String msg = "Factory method '" + factoryMethod.getName() + "' threw exception with message: " +
|
|
||||||
ex.getTargetException().getMessage();
|
|
||||||
if (bd.getFactoryBeanName() != null && owner instanceof ConfigurableBeanFactory cbf &&
|
|
||||||
cbf.isCurrentlyInCreation(bd.getFactoryBeanName())) {
|
|
||||||
msg = "Circular reference involving containing bean '" + bd.getFactoryBeanName() + "' - consider " +
|
|
||||||
"declaring the factory method as static for independence from its containing instance. " + msg;
|
|
||||||
}
|
}
|
||||||
throw new BeanInstantiationException(factoryMethod, msg, ex.getTargetException());
|
catch (InvocationTargetException ex) {
|
||||||
}
|
String msg = "Factory method '" + factoryMethod.getName() + "' threw exception with message: " +
|
||||||
|
ex.getTargetException().getMessage();
|
||||||
|
if (bd.getFactoryBeanName() != null && owner instanceof ConfigurableBeanFactory cbf &&
|
||||||
|
cbf.isCurrentlyInCreation(bd.getFactoryBeanName())) {
|
||||||
|
msg = "Circular reference involving containing bean '" + bd.getFactoryBeanName() + "' - consider " +
|
||||||
|
"declaring the factory method as static for independence from its containing instance. " + msg;
|
||||||
|
}
|
||||||
|
throw new BeanInstantiationException(factoryMethod, msg, ex.getTargetException());
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue