我有多个用 @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
.
其他解析器是
ExceptionHandlerExceptionResolver
ResponseStatusExceptionResolver
DefaultHandlerExceptionResolver
按该顺序注册。为了这个问题的目的,我们只关心 ExceptionHandlerExceptionResolver
.
An
AbstractHandlerMethodExceptionResolver
that resolves exceptions through@ExceptionHandler
methods.
在上下文初始化时,Spring 将生成一个 ControllerAdviceBean
对于每个 @ControllerAdvice
它检测到的带注释的类。 ExceptionHandlerExceptionResolver
将从上下文中检索这些异常,并使用 AnnotationAwareOrderComparator
对它们进行排序。其中
is an extension of
OrderComparator
that supports Spring'sOrdered
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
并给它一个适当的值。