Support Ordered interface for @ControllerAdvice beans

Closes gh-23163
This commit is contained in:
Sam Brannen
2019-06-23 19:11:26 +03:00
parent 978adbdae7
commit 9239ab1891
3 changed files with 34 additions and 32 deletions

View File

@@ -33,15 +33,15 @@ import org.springframework.stereotype.Component;
* multiple {@code @Controller} classes.
*
* <p>Classes with {@code @ControllerAdvice} can be declared explicitly as Spring
* beans or auto-detected via classpath scanning. All such beans are sorted via
* {@link org.springframework.core.annotation.AnnotationAwareOrderComparator
* AnnotationAwareOrderComparator}, based on
* {@link org.springframework.core.annotation.Order @Order} and
* {@link org.springframework.core.Ordered Ordered}, and applied in that order
* at runtime. For handling exceptions, an {@code @ExceptionHandler} will be
* picked on the first advice with a matching exception handler method. For
* model attributes and {@code InitBinder} initialization, {@code @ModelAttribute}
* and {@code @InitBinder} methods will also follow {@code @ControllerAdvice} order.
* beans or auto-detected via classpath scanning. All such beans are sorted based
* on {@link org.springframework.core.Ordered Ordered},
* {@link org.springframework.core.annotation.Order @Order}, and
* {@link javax.annotation.Priority @Priority} (in that order of precedence),
* and applied in that order at runtime. For handling exceptions, an
* {@code @ExceptionHandler} will be picked on the first advice with a matching
* exception handler method. For model attributes and {@code InitBinder}
* initialization, {@code @ModelAttribute} and {@code @InitBinder} methods will
* also follow {@code @ControllerAdvice} order.
*
* <p>Note: For {@code @ExceptionHandler} methods, a root exception match will be
* preferred to just matching a cause of the current exception, among the handler

View File

@@ -67,7 +67,8 @@ public class ControllerAdviceBean implements Ordered {
@Nullable
private final BeanFactory beanFactory;
private final int order;
@Nullable
private Integer order;
/**
@@ -81,7 +82,6 @@ public class ControllerAdviceBean implements Ordered {
this.beanType = ClassUtils.getUserClass(bean.getClass());
this.beanTypePredicate = createBeanTypePredicate(this.beanType);
this.beanFactory = null;
this.order = initOrderFromBean(bean);
}
/**
@@ -117,16 +117,32 @@ public class ControllerAdviceBean implements Ordered {
this.beanTypePredicate = (controllerAdvice != null ? createBeanTypePredicate(controllerAdvice)
: createBeanTypePredicate(this.beanType));
this.beanFactory = beanFactory;
this.order = initOrderFromBeanType(this.beanType);
}
/**
* Return the order value extracted from the {@link ControllerAdvice}
* annotation, or {@link Ordered#LOWEST_PRECEDENCE} otherwise.
* Get the order value for the contained bean.
* <p>As of Spring Framework 5.2, the order value is lazily retrieved using
* the following algorithm and cached.
* <ul>
* <li>If the {@linkplain #resolveBean resolved bean} implements {@link Ordered},
* use the value returned by {@link Ordered#getOrder()}.</li>
* <li>Otherwise use the value returned by {@link OrderUtils#getOrder(Class, int)}
* with {@link Ordered#LOWEST_PRECEDENCE} used as the default order value.</li>
* </ul>
* @see #resolveBean()
*/
@Override
public int getOrder() {
if (this.order == null) {
Object resolvedBean = resolveBean();
if (resolvedBean instanceof Ordered) {
this.order = ((Ordered) resolvedBean).getOrder();
}
else {
this.order = OrderUtils.getOrder(getBeanType(), Ordered.LOWEST_PRECEDENCE);
}
}
return this.order;
}
@@ -236,16 +252,4 @@ public class ControllerAdviceBean implements Ordered {
return HandlerTypePredicate.forAnyHandlerType();
}
private static int initOrderFromBean(Object bean) {
return (bean instanceof Ordered ? ((Ordered) bean).getOrder() : initOrderFromBeanType(bean.getClass()));
}
private static int initOrderFromBeanType(@Nullable Class<?> beanType) {
Integer order = null;
if (beanType != null) {
order = OrderUtils.getOrder(beanType);
}
return (order != null ? order : Ordered.LOWEST_PRECEDENCE);
}
}