Skip to content

Commit 6de624d

Browse files
committed
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
1 parent 0c319a8 commit 6de624d

File tree

2 files changed

+52
-37
lines changed

2 files changed

+52
-37
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanInstanceSupplier.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -213,14 +213,7 @@ private T invokeBeanSupplier(Executable executable, ThrowingSupplier<T> beanSupp
213213
if (!(executable instanceof Method method)) {
214214
return beanSupplier.get();
215215
}
216-
Method priorInvokedFactoryMethod = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
217-
try {
218-
SimpleInstantiationStrategy.setCurrentlyInvokedFactoryMethod(method);
219-
return beanSupplier.get();
220-
}
221-
finally {
222-
SimpleInstantiationStrategy.setCurrentlyInvokedFactoryMethod(priorInvokedFactoryMethod);
223-
}
216+
return SimpleInstantiationStrategy.instantiateWithFactoryMethod(method, beanSupplier::get);
224217
}
225218

226219
@Nullable

spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleInstantiationStrategy.java

Lines changed: 51 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.lang.Nullable;
2828
import org.springframework.util.ReflectionUtils;
2929
import org.springframework.util.StringUtils;
30+
import org.springframework.util.function.ThrowingSupplier;
3031

3132
/**
3233
* Simple object instantiation strategy for use in a BeanFactory.
@@ -59,7 +60,9 @@ public static Method getCurrentlyInvokedFactoryMethod() {
5960
* the current value, if any.
6061
* @param method the factory method currently being invoked or {@code null}
6162
* @since 6.0
63+
* @deprecated in favor of {@link #instantiateWithFactoryMethod(Method, ThrowingSupplier)}
6264
*/
65+
@Deprecated(since = "6.2", forRemoval = true)
6366
public static void setCurrentlyInvokedFactoryMethod(@Nullable Method method) {
6467
if (method != null) {
6568
currentlyInvokedFactoryMethod.set(method);
@@ -69,6 +72,31 @@ public static void setCurrentlyInvokedFactoryMethod(@Nullable Method method) {
6972
}
7073
}
7174

75+
/**
76+
* Invoke the given {@code instanceSupplier} with the factory method exposed
77+
* as being invoked.
78+
* @param method the factory method to expose
79+
* @param instanceSupplier the instance supplier
80+
* @param <T> the type of the instance
81+
* @return the result of the instance supplier
82+
* @since 6.2
83+
*/
84+
public static <T> T instantiateWithFactoryMethod(Method method, ThrowingSupplier<T> instanceSupplier) {
85+
Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
86+
try {
87+
currentlyInvokedFactoryMethod.set(method);
88+
return instanceSupplier.get();
89+
}
90+
finally {
91+
if (priorInvokedFactoryMethod != null) {
92+
currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
93+
}
94+
else {
95+
currentlyInvokedFactoryMethod.remove();
96+
}
97+
}
98+
}
99+
72100

73101
@Override
74102
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
@@ -137,46 +165,40 @@ protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable
137165
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
138166
@Nullable Object factoryBean, Method factoryMethod, Object... args) {
139167

140-
try {
141-
ReflectionUtils.makeAccessible(factoryMethod);
142-
143-
Method priorInvokedFactoryMethod = getCurrentlyInvokedFactoryMethod();
168+
return instantiateWithFactoryMethod(factoryMethod, () -> {
144169
try {
145-
setCurrentlyInvokedFactoryMethod(factoryMethod);
170+
ReflectionUtils.makeAccessible(factoryMethod);
146171
Object result = factoryMethod.invoke(factoryBean, args);
147172
if (result == null) {
148173
result = new NullBean();
149174
}
150175
return result;
151176
}
152-
finally {
153-
setCurrentlyInvokedFactoryMethod(priorInvokedFactoryMethod);
177+
catch (IllegalArgumentException ex) {
178+
if (factoryBean != null && !factoryMethod.getDeclaringClass().isAssignableFrom(factoryBean.getClass())) {
179+
throw new BeanInstantiationException(factoryMethod,
180+
"Illegal factory instance for factory method '" + factoryMethod.getName() + "'; " +
181+
"instance: " + factoryBean.getClass().getName(), ex);
182+
}
183+
throw new BeanInstantiationException(factoryMethod,
184+
"Illegal arguments to factory method '" + factoryMethod.getName() + "'; " +
185+
"args: " + StringUtils.arrayToCommaDelimitedString(args), ex);
154186
}
155-
}
156-
catch (IllegalArgumentException ex) {
157-
if (factoryBean != null && !factoryMethod.getDeclaringClass().isAssignableFrom(factoryBean.getClass())) {
187+
catch (IllegalAccessException ex) {
158188
throw new BeanInstantiationException(factoryMethod,
159-
"Illegal factory instance for factory method '" + factoryMethod.getName() + "'; " +
160-
"instance: " + factoryBean.getClass().getName(), ex);
189+
"Cannot access factory method '" + factoryMethod.getName() + "'; is it public?", ex);
161190
}
162-
throw new BeanInstantiationException(factoryMethod,
163-
"Illegal arguments to factory method '" + factoryMethod.getName() + "'; " +
164-
"args: " + StringUtils.arrayToCommaDelimitedString(args), ex);
165-
}
166-
catch (IllegalAccessException ex) {
167-
throw new BeanInstantiationException(factoryMethod,
168-
"Cannot access factory method '" + factoryMethod.getName() + "'; is it public?", ex);
169-
}
170-
catch (InvocationTargetException ex) {
171-
String msg = "Factory method '" + factoryMethod.getName() + "' threw exception with message: " +
172-
ex.getTargetException().getMessage();
173-
if (bd.getFactoryBeanName() != null && owner instanceof ConfigurableBeanFactory cbf &&
174-
cbf.isCurrentlyInCreation(bd.getFactoryBeanName())) {
175-
msg = "Circular reference involving containing bean '" + bd.getFactoryBeanName() + "' - consider " +
176-
"declaring the factory method as static for independence from its containing instance. " + msg;
191+
catch (InvocationTargetException ex) {
192+
String msg = "Factory method '" + factoryMethod.getName() + "' threw exception with message: " +
193+
ex.getTargetException().getMessage();
194+
if (bd.getFactoryBeanName() != null && owner instanceof ConfigurableBeanFactory cbf &&
195+
cbf.isCurrentlyInCreation(bd.getFactoryBeanName())) {
196+
msg = "Circular reference involving containing bean '" + bd.getFactoryBeanName() + "' - consider " +
197+
"declaring the factory method as static for independence from its containing instance. " + msg;
198+
}
199+
throw new BeanInstantiationException(factoryMethod, msg, ex.getTargetException());
177200
}
178-
throw new BeanInstantiationException(factoryMethod, msg, ex.getTargetException());
179-
}
201+
});
180202
}
181203

182204
}

0 commit comments

Comments
 (0)