我有多个用 @ControllerAdvice 注释的类,每个类都有一个 @ExceptionHandler 方法。
@ControllerAdvice
@ExceptionHandler
一个处理 Exception 的意图是,如果找不到更具体的处理程序,就应该使用它。
Exception
遗憾的是,Spring似乎总是使用最通用的案例( Exception ),而不是更具体的案例(例如, IOException )。
IOException
这就是人们期望Spring行为的方式吗?我正在尝试模拟泽西的模式,该模式评估每个 ExceptionMapper (等效组件),以确定它处理的声明类型与抛出的异常有多远,并且总是使用最近的祖先。
ExceptionMapper
发布于 2013-10-21 17:18:55
这就是人们期望Spring行为的方式吗?
从Spring4.3.7开始,以下是Spring的行为方式:它使用 HandlerExceptionResolver 实例来处理处理程序方法引发的异常。
HandlerExceptionResolver
默认情况下,web配置注册一个 HandlerExceptionResolver bean, HandlerExceptionResolverComposite ,它
HandlerExceptionResolverComposite
委托给其他 HandlerExceptionResolvers 的列表。
HandlerExceptionResolvers
其他的解析器是
ExceptionHandlerExceptionResolver
ResponseStatusExceptionResolver
DefaultHandlerExceptionResolver
按该顺序登记。就这个问题而言,我们只关心 ExceptionHandlerExceptionResolver 。
通过 AbstractHandlerMethodExceptionResolver 方法解析异常的 @ExceptionHandler 。
AbstractHandlerMethodExceptionResolver
在上下文初始化时,Spring将为它检测到的每个 @ControllerAdvice 注释类生成一个 @ControllerAdvice 。 ExceptionHandlerExceptionResolver 将从上下文中检索它们,并使用以下 AnnotationAwareOrderComparator 对它们进行排序:
AnnotationAwareOrderComparator
是 OrderComparator 的扩展,它支持Spring的 Ordered 接口以及 @Order 和 @Priority 注释,其中order值由order实例提供,覆盖静态定义的注释值(如果有的话)。
OrderComparator
Ordered
@Order
@Priority
然后为每个 ControllerAdviceBean 实例注册一个 ControllerAdviceBean (将可用的 @ExceptionHandler 方法映射到它们要处理的异常类型)。最后,它们以相同的顺序添加到 LinkedHashMap (保留迭代顺序)中。
ControllerAdviceBean
LinkedHashMap
当出现异常时, ExceptionHandlerExceptionResolver 将遍历这些 ExceptionHandlerMethodResolver ,并使用能够处理异常的第一个异常。
ExceptionHandlerMethodResolver
因此,这里的要点是:如果您有一个带有 @ExceptionHandler for Exception 的 @ExceptionHandler ,它在另一个 @ControllerAdvice 类之前注册,而另一个 @ControllerAdvice 类有一个更具体的异常,比如 IOException ,那么第一个将被调用。如前所述,您可以通过让 @ControllerAdvice 注释的类实现 Ordered 或用 @Order 或 @Priority 注释它并给它适当的值来控制注册顺序。
发布于 2013-12-09 14:47:08
索提里奥斯·德里马诺利的回答非常有帮助,在进一步的调查中,我们发现,无论如何,在春季3.2.4,寻找@ControllerAdvice注释的代码也会检查@Order注解的存在,并对ControllerAdviceBeans列表进行排序。
没有@Order注释的所有控制器的默认顺序是Ordered#LOWEST_PRECEDENCE,这意味着如果您有一个需要最低优先级的控制器,那么所有控制器都需要一个更高的顺序。
下面是一个示例,演示如何使用两个带有ControllerAdvice和Order注释的异常处理程序类,这些类可以在发生UserProfileException或RuntimeException时提供适当的响应。
class UserProfileException extends RuntimeException { @ControllerAdvice @Order(Ordered.HIGHEST_PRECEDENCE) class UserProfileExceptionHandler { @ExceptionHandler(UserProfileException) @ResponseBody ResponseEntity<ErrorResponse> handleUserProfileException() { @ControllerAdvice @Order(Ordered.LOWEST_PRECEDENCE) class DefaultExceptionHandler { @ExceptionHandler(RuntimeException) @ResponseBody ResponseEntity<ErrorResponse> handleRuntimeException() { }
享受吧!
发布于 2013-12-16 12:09:45
可以使用 @Order 注释更改异常处理程序的顺序。
例如:
import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.web.bind.annotation.ControllerAdvice; @ControllerAdvice