Skip to content

Commit b888f36

Browse files
committed
Document ControllerAdviceBean as internal usage
This commit documents `ControllerAdviceBean` as internal usage, as it is not meant for application to manually create controller advice bean instances. This also refactors the existing partial implementation of the support for creating controller advice beans "programmatically". Closes gh-32776
1 parent 94e2bef commit b888f36

File tree

3 files changed

+138
-175
lines changed

3 files changed

+138
-175
lines changed

spring-web/src/main/java/org/springframework/web/method/ControllerAdviceBean.java

Lines changed: 30 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import org.springframework.context.ConfigurableApplicationContext;
3434
import org.springframework.core.OrderComparator;
3535
import org.springframework.core.Ordered;
36-
import org.springframework.core.annotation.AnnotatedElementUtils;
3736
import org.springframework.core.annotation.OrderUtils;
3837
import org.springframework.lang.Nullable;
3938
import org.springframework.util.Assert;
@@ -43,10 +42,11 @@
4342
/**
4443
* Encapsulates information about an {@link ControllerAdvice @ControllerAdvice}
4544
* Spring-managed bean without necessarily requiring it to be instantiated.
45+
* The {@link #findAnnotatedBeans(ApplicationContext)} method can be used to
46+
* discover such beans.
4647
*
47-
* <p>The {@link #findAnnotatedBeans(ApplicationContext)} method can be used to
48-
* discover such beans. However, a {@code ControllerAdviceBean} may be created
49-
* from any object, including ones without an {@code @ControllerAdvice} annotation.
48+
* <p>This class is internal to Spring Framework and is not meant to be used
49+
* by applications to manually create {@code @ControllerAdvice} beans.
5050
*
5151
* @author Rossen Stoyanchev
5252
* @author Brian Clozel
@@ -56,11 +56,7 @@
5656
*/
5757
public class ControllerAdviceBean implements Ordered {
5858

59-
/**
60-
* Reference to the actual bean instance or a {@code String} representing
61-
* the bean name.
62-
*/
63-
private final Object beanOrName;
59+
private final String beanName;
6460

6561
private final boolean isSingleton;
6662

@@ -76,60 +72,33 @@ public class ControllerAdviceBean implements Ordered {
7672

7773
private final HandlerTypePredicate beanTypePredicate;
7874

79-
@Nullable
8075
private final BeanFactory beanFactory;
8176

8277
@Nullable
8378
private Integer order;
8479

8580

86-
/**
87-
* Create a {@code ControllerAdviceBean} using the given bean instance.
88-
* @param bean the bean instance
89-
*/
90-
public ControllerAdviceBean(Object bean) {
91-
Assert.notNull(bean, "Bean must not be null");
92-
this.beanOrName = bean;
93-
this.isSingleton = true;
94-
this.resolvedBean = bean;
95-
this.beanType = ClassUtils.getUserClass(bean.getClass());
96-
this.beanTypePredicate = createBeanTypePredicate(this.beanType);
97-
this.beanFactory = null;
98-
}
99-
100-
/**
101-
* Create a {@code ControllerAdviceBean} using the given bean name and
102-
* {@code BeanFactory}.
103-
* @param beanName the name of the bean
104-
* @param beanFactory a {@code BeanFactory} to retrieve the bean type initially
105-
* and later to resolve the actual bean
106-
*/
107-
public ControllerAdviceBean(String beanName, BeanFactory beanFactory) {
108-
this(beanName, beanFactory, null);
109-
}
110-
11181
/**
11282
* Create a {@code ControllerAdviceBean} using the given bean name,
11383
* {@code BeanFactory}, and {@link ControllerAdvice @ControllerAdvice}
11484
* annotation.
11585
* @param beanName the name of the bean
11686
* @param beanFactory a {@code BeanFactory} to retrieve the bean type initially
11787
* and later to resolve the actual bean
118-
* @param controllerAdvice the {@code @ControllerAdvice} annotation for the
119-
* bean, or {@code null} if not yet retrieved
88+
* @param controllerAdvice the {@code @ControllerAdvice} annotation for the bean
12089
* @since 5.2
12190
*/
122-
public ControllerAdviceBean(String beanName, BeanFactory beanFactory, @Nullable ControllerAdvice controllerAdvice) {
91+
public ControllerAdviceBean(String beanName, BeanFactory beanFactory, ControllerAdvice controllerAdvice) {
12392
Assert.hasText(beanName, "Bean name must contain text");
12493
Assert.notNull(beanFactory, "BeanFactory must not be null");
12594
Assert.isTrue(beanFactory.containsBean(beanName), () -> "BeanFactory [" + beanFactory +
12695
"] does not contain specified controller advice bean '" + beanName + "'");
96+
Assert.notNull(controllerAdvice, "ControllerAdvice must not be null");
12797

128-
this.beanOrName = beanName;
98+
this.beanName = beanName;
12999
this.isSingleton = beanFactory.isSingleton(beanName);
130100
this.beanType = getBeanType(beanName, beanFactory);
131-
this.beanTypePredicate = (controllerAdvice != null ? createBeanTypePredicate(controllerAdvice) :
132-
createBeanTypePredicate(this.beanType));
101+
this.beanTypePredicate = createBeanTypePredicate(controllerAdvice);
133102
this.beanFactory = beanFactory;
134103
}
135104

@@ -158,31 +127,24 @@ public ControllerAdviceBean(String beanName, BeanFactory beanFactory, @Nullable
158127
@Override
159128
public int getOrder() {
160129
if (this.order == null) {
161-
String beanName = null;
162130
Object resolvedBean = null;
163-
if (this.beanFactory != null && this.beanOrName instanceof String stringBeanName) {
164-
beanName = stringBeanName;
165-
String targetBeanName = ScopedProxyUtils.getTargetBeanName(beanName);
166-
boolean isScopedProxy = this.beanFactory.containsBean(targetBeanName);
167-
// Avoid eager @ControllerAdvice bean resolution for scoped proxies,
168-
// since attempting to do so during context initialization would result
169-
// in an exception due to the current absence of the scope. For example,
170-
// an HTTP request or session scope is not active during initialization.
171-
if (!isScopedProxy && !ScopedProxyUtils.isScopedTarget(beanName)) {
172-
resolvedBean = resolveBean();
173-
}
174-
}
175-
else {
131+
String targetBeanName = ScopedProxyUtils.getTargetBeanName(this.beanName);
132+
boolean isScopedProxy = this.beanFactory.containsBean(targetBeanName);
133+
// Avoid eager @ControllerAdvice bean resolution for scoped proxies,
134+
// since attempting to do so during context initialization would result
135+
// in an exception due to the current absence of the scope. For example,
136+
// an HTTP request or session scope is not active during initialization.
137+
if (!isScopedProxy && !ScopedProxyUtils.isScopedTarget(this.beanName)) {
176138
resolvedBean = resolveBean();
177139
}
178140

179141
if (resolvedBean instanceof Ordered ordered) {
180142
this.order = ordered.getOrder();
181143
}
182144
else {
183-
if (beanName != null && this.beanFactory instanceof ConfigurableBeanFactory cbf) {
145+
if (this.beanFactory instanceof ConfigurableBeanFactory cbf) {
184146
try {
185-
BeanDefinition bd = cbf.getMergedBeanDefinition(beanName);
147+
BeanDefinition bd = cbf.getMergedBeanDefinition(this.beanName);
186148
if (bd instanceof RootBeanDefinition rbd) {
187149
Method factoryMethod = rbd.getResolvedFactoryMethod();
188150
if (factoryMethod != null) {
@@ -225,9 +187,7 @@ public Class<?> getBeanType() {
225187
*/
226188
public Object resolveBean() {
227189
if (this.resolvedBean == null) {
228-
// this.beanOrName must be a String representing the bean name if
229-
// this.resolvedBean is null.
230-
Object resolvedBean = obtainBeanFactory().getBean((String) this.beanOrName);
190+
Object resolvedBean = this.beanFactory.getBean(this.beanName);
231191
// Don't cache non-singletons (e.g., prototypes).
232192
if (!this.isSingleton) {
233193
return resolvedBean;
@@ -237,11 +197,6 @@ public Object resolveBean() {
237197
return this.resolvedBean;
238198
}
239199

240-
private BeanFactory obtainBeanFactory() {
241-
Assert.state(this.beanFactory != null, "No BeanFactory set");
242-
return this.beanFactory;
243-
}
244-
245200
/**
246201
* Check whether the given bean type should be advised by this
247202
* {@code ControllerAdviceBean}.
@@ -257,17 +212,17 @@ public boolean isApplicableToBeanType(@Nullable Class<?> beanType) {
257212
@Override
258213
public boolean equals(@Nullable Object other) {
259214
return (this == other || (other instanceof ControllerAdviceBean that &&
260-
this.beanOrName.equals(that.beanOrName) && this.beanFactory == that.beanFactory));
215+
this.beanName.equals(that.beanName) && this.beanFactory == that.beanFactory));
261216
}
262217

263218
@Override
264219
public int hashCode() {
265-
return this.beanOrName.hashCode();
220+
return this.beanName.hashCode();
266221
}
267222

268223
@Override
269224
public String toString() {
270-
return this.beanOrName.toString();
225+
return this.beanName;
271226
}
272227

273228

@@ -308,22 +263,13 @@ private static Class<?> getBeanType(String beanName, BeanFactory beanFactory) {
308263
return (beanType != null ? ClassUtils.getUserClass(beanType) : null);
309264
}
310265

311-
private static HandlerTypePredicate createBeanTypePredicate(@Nullable Class<?> beanType) {
312-
ControllerAdvice controllerAdvice = (beanType != null ?
313-
AnnotatedElementUtils.findMergedAnnotation(beanType, ControllerAdvice.class) : null);
314-
return createBeanTypePredicate(controllerAdvice);
315-
}
316-
317-
private static HandlerTypePredicate createBeanTypePredicate(@Nullable ControllerAdvice controllerAdvice) {
318-
if (controllerAdvice != null) {
319-
return HandlerTypePredicate.builder()
320-
.basePackage(controllerAdvice.basePackages())
321-
.basePackageClass(controllerAdvice.basePackageClasses())
322-
.assignableType(controllerAdvice.assignableTypes())
323-
.annotation(controllerAdvice.annotations())
324-
.build();
325-
}
326-
return HandlerTypePredicate.forAnyHandlerType();
266+
private static HandlerTypePredicate createBeanTypePredicate(ControllerAdvice controllerAdvice) {
267+
return HandlerTypePredicate.builder()
268+
.basePackage(controllerAdvice.basePackages())
269+
.basePackageClass(controllerAdvice.basePackageClasses())
270+
.assignableType(controllerAdvice.assignableTypes())
271+
.annotation(controllerAdvice.annotations())
272+
.build();
327273
}
328274

329275
}

0 commit comments

Comments
 (0)