Skip to main content
 首页 » 编程设计

spring-mvc之设置多个@ControllerAdvice @ExceptionHandlers的优先级

2024年02月27日22webabcd

我有多个用 @ControllerAdvice 注释的类,每个类都有一个 @ExceptionHandler 方法。

处理异常的目的是,如果没有找到更具体的处理程序,则应该使用它。

遗憾的是 Spring MVC 似乎总是使用最通用的情况(Exception),而不是更具体的情况(例如 IOException)。

这是人们所期望的 Spring MVC 的行为方式吗?我正在尝试模拟 Jersey 中的一种模式,该模式评估每个 ExceptionMapper(等效组件)以确定它处理的声明类型与已引发的异常的距离有多远,并且始终使用最近的祖先。

请您参考如下方法:

Is this how one would expect Spring MVC to behave?

从 Spring 4.3.7 开始,Spring MVC 的行为方式如下:它使用 HandlerExceptionResolver实例来处理处理程序方法抛出的异常。

默认情况下,Web MVC 配置注册一个 HandlerExceptionResolver bean,即 HandlerExceptionResolverComposite ,其中

delegates to a list of other HandlerExceptionResolvers.

其他解析器是

  1. ExceptionHandlerExceptionResolver
  2. ResponseStatusExceptionResolver
  3. DefaultHandlerExceptionResolver

按该顺序注册。为了这个问题的目的,我们只关心 ExceptionHandlerExceptionResolver .

An AbstractHandlerMethodExceptionResolver that resolves exceptions through @ExceptionHandler methods.

在上下文初始化时,Spring 将生成一个 ControllerAdviceBean对于每个 @ControllerAdvice它检测到的带注释的类。 ExceptionHandlerExceptionResolver 将从上下文中检索这些异常,并使用 AnnotationAwareOrderComparator 对它们进行排序。其中

is an extension of OrderComparator that supports Spring's Ordered interface as well as the @Order and @Priority annotations, with an order value provided by an Ordered instance overriding a statically defined annotation value (if any).

然后它会注册一个 ExceptionHandlerMethodResolver对于每个 ControllerAdviceBean 实例(将可用的 @ExceptionHandler 方法映射到它们要处理的异常类型)。它们最终以相同的顺序添加到 LinkedHashMap(保留迭代顺序)。

当异常发生时,ExceptionHandlerExceptionResolver将迭代这些ExceptionHandlerMethodResolver并使用第一个可以处理异常的。

所以这里的要点是:如果您有一个 @ControllerAdvice ,其中包含一个用于 Exception@ExceptionHandler ,并且在另一个 之前注册@ControllerAdvice 类,带有一个 @ExceptionHandler 来处理更具体的异常,例如 IOException,第一个将被调用。如前所述,您可以通过让 @ControllerAdvice 带注释的类实现 Ordered 来控制注册顺序。或用 @Order 对其进行注释或@Priority并给它一个适当的值。