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:
Stéphane Nicoll 2024-07-10 13:12:12 +02:00
parent 0c319a89d7
commit 6de624d537
2 changed files with 53 additions and 38 deletions

View File

@ -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

View File

@ -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,22 +165,15 @@ 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) {
return instantiateWithFactoryMethod(factoryMethod, () -> {
try { try {
ReflectionUtils.makeAccessible(factoryMethod); ReflectionUtils.makeAccessible(factoryMethod);
Method priorInvokedFactoryMethod = getCurrentlyInvokedFactoryMethod();
try {
setCurrentlyInvokedFactoryMethod(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 {
setCurrentlyInvokedFactoryMethod(priorInvokedFactoryMethod);
}
}
catch (IllegalArgumentException ex) { catch (IllegalArgumentException ex) {
if (factoryBean != null && !factoryMethod.getDeclaringClass().isAssignableFrom(factoryBean.getClass())) { if (factoryBean != null && !factoryMethod.getDeclaringClass().isAssignableFrom(factoryBean.getClass())) {
throw new BeanInstantiationException(factoryMethod, throw new BeanInstantiationException(factoryMethod,
@ -177,6 +198,7 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
} }
throw new BeanInstantiationException(factoryMethod, msg, ex.getTargetException()); throw new BeanInstantiationException(factoryMethod, msg, ex.getTargetException());
} }
});
} }
} }