16
16
17
17
package org .springframework .web .method ;
18
18
19
+ import java .lang .reflect .AnnotatedElement ;
20
+ import java .lang .reflect .Method ;
19
21
import java .util .ArrayList ;
20
22
import java .util .List ;
21
23
22
24
import org .springframework .aop .scope .ScopedProxyUtils ;
23
25
import org .springframework .beans .factory .BeanFactory ;
24
26
import org .springframework .beans .factory .BeanFactoryUtils ;
27
+ import org .springframework .beans .factory .ListableBeanFactory ;
28
+ import org .springframework .beans .factory .NoSuchBeanDefinitionException ;
29
+ import org .springframework .beans .factory .config .BeanDefinition ;
30
+ import org .springframework .beans .factory .config .ConfigurableBeanFactory ;
31
+ import org .springframework .beans .factory .support .RootBeanDefinition ;
25
32
import org .springframework .context .ApplicationContext ;
33
+ import org .springframework .context .ConfigurableApplicationContext ;
26
34
import org .springframework .core .OrderComparator ;
27
35
import org .springframework .core .Ordered ;
28
36
import org .springframework .core .annotation .AnnotatedElementUtils ;
@@ -128,7 +136,7 @@ public ControllerAdviceBean(String beanName, BeanFactory beanFactory, @Nullable
128
136
129
137
/**
130
138
* Get the order value for the contained bean.
131
- * <p>As of Spring Framework 5.2 , the order value is lazily retrieved using
139
+ * <p>As of Spring Framework 5.3 , the order value is lazily retrieved using
132
140
* the following algorithm and cached. Note, however, that a
133
141
* {@link ControllerAdvice @ControllerAdvice} bean that is configured as a
134
142
* scoped bean — for example, as a request-scoped or session-scoped
@@ -137,6 +145,8 @@ public ControllerAdviceBean(String beanName, BeanFactory beanFactory, @Nullable
137
145
* <ul>
138
146
* <li>If the {@linkplain #resolveBean resolved bean} implements {@link Ordered},
139
147
* use the value returned by {@link Ordered#getOrder()}.</li>
148
+ * <li>If the {@linkplain org.springframework.context.annotation.Bean factory method}
149
+ * is known, use the value returned by {@link OrderUtils#getOrder(AnnotatedElement)}.
140
150
* <li>If the {@linkplain #getBeanType() bean type} is known, use the value returned
141
151
* by {@link OrderUtils#getOrder(Class, int)} with {@link Ordered#LOWEST_PRECEDENCE}
142
152
* used as the default order value.</li>
@@ -148,9 +158,10 @@ public ControllerAdviceBean(String beanName, BeanFactory beanFactory, @Nullable
148
158
@ Override
149
159
public int getOrder () {
150
160
if (this .order == null ) {
161
+ String beanName = null ;
151
162
Object resolvedBean = null ;
152
163
if (this .beanFactory != null && this .beanOrName instanceof String ) {
153
- String beanName = (String ) this .beanOrName ;
164
+ beanName = (String ) this .beanOrName ;
154
165
String targetBeanName = ScopedProxyUtils .getTargetBeanName (beanName );
155
166
boolean isScopedProxy = this .beanFactory .containsBean (targetBeanName );
156
167
// Avoid eager @ControllerAdvice bean resolution for scoped proxies,
@@ -168,11 +179,30 @@ public int getOrder() {
168
179
if (resolvedBean instanceof Ordered ) {
169
180
this .order = ((Ordered ) resolvedBean ).getOrder ();
170
181
}
171
- else if (this .beanType != null ) {
172
- this .order = OrderUtils .getOrder (this .beanType , Ordered .LOWEST_PRECEDENCE );
173
- }
174
182
else {
175
- this .order = Ordered .LOWEST_PRECEDENCE ;
183
+ if (beanName != null && this .beanFactory instanceof ConfigurableBeanFactory ) {
184
+ ConfigurableBeanFactory cbf = (ConfigurableBeanFactory ) this .beanFactory ;
185
+ try {
186
+ BeanDefinition bd = cbf .getMergedBeanDefinition (beanName );
187
+ if (bd instanceof RootBeanDefinition ) {
188
+ Method factoryMethod = ((RootBeanDefinition ) bd ).getResolvedFactoryMethod ();
189
+ if (factoryMethod != null ) {
190
+ this .order = OrderUtils .getOrder (factoryMethod );
191
+ }
192
+ }
193
+ }
194
+ catch (NoSuchBeanDefinitionException ex ) {
195
+ // ignore -> probably a manually registered singleton
196
+ }
197
+ }
198
+ if (this .order == null ) {
199
+ if (this .beanType != null ) {
200
+ this .order = OrderUtils .getOrder (this .beanType , Ordered .LOWEST_PRECEDENCE );
201
+ }
202
+ else {
203
+ this .order = Ordered .LOWEST_PRECEDENCE ;
204
+ }
205
+ }
176
206
}
177
207
}
178
208
return this .order ;
@@ -260,14 +290,19 @@ public String toString() {
260
290
* @see Ordered
261
291
*/
262
292
public static List <ControllerAdviceBean > findAnnotatedBeans (ApplicationContext context ) {
293
+ ListableBeanFactory beanFactory = context ;
294
+ if (context instanceof ConfigurableApplicationContext ) {
295
+ // Use internal BeanFactory for potential downcast to ConfigurableBeanFactory above
296
+ beanFactory = ((ConfigurableApplicationContext ) context ).getBeanFactory ();
297
+ }
263
298
List <ControllerAdviceBean > adviceBeans = new ArrayList <>();
264
- for (String name : BeanFactoryUtils .beanNamesForTypeIncludingAncestors (context , Object .class )) {
299
+ for (String name : BeanFactoryUtils .beanNamesForTypeIncludingAncestors (beanFactory , Object .class )) {
265
300
if (!ScopedProxyUtils .isScopedTarget (name )) {
266
- ControllerAdvice controllerAdvice = context .findAnnotationOnBean (name , ControllerAdvice .class );
301
+ ControllerAdvice controllerAdvice = beanFactory .findAnnotationOnBean (name , ControllerAdvice .class );
267
302
if (controllerAdvice != null ) {
268
303
// Use the @ControllerAdvice annotation found by findAnnotationOnBean()
269
304
// in order to avoid a subsequent lookup of the same annotation.
270
- adviceBeans .add (new ControllerAdviceBean (name , context , controllerAdvice ));
305
+ adviceBeans .add (new ControllerAdviceBean (name , beanFactory , controllerAdvice ));
271
306
}
272
307
}
273
308
}
0 commit comments