我有多个用@ControllerAdvice
注释的类,每个类中都带有@ExceptionHandler
方法。
一个人处理Exception
的目的是,如果找不到更多特定的处理程序,则应使用它。
不幸的是,Spring MVC似乎总是使用最通用的情况(Exception
),而不是更具体的情况(例如IOException
)。
这是人们期望Spring MVC表现的方式吗?我正在尝试从Jersey模拟一个模式,该模式评估每个ExceptionMapper
(等效组件)以确定它处理的声明类型与引发的异常之间的距离,并且始终使用最接近的祖先。
最佳答案
从Spring 4.3.7开始,Spring MVC的行为如下:它使用 HandlerExceptionResolver
实例来处理由处理程序方法引发的异常。
默认情况下,Web MVC配置会注册一个HandlerExceptionResolver
bean HandlerExceptionResolverComposite
,
那些其他解析器是
ExceptionHandlerExceptionResolver
ResponseStatusExceptionResolver
DefaultHandlerExceptionResolver
以该顺序注册。出于这个问题的目的,我们只关心
ExceptionHandlerExceptionResolver
。在上下文初始化时,Spring将为它检测到的每个带有
ControllerAdviceBean
的带注释的类生成一个 @ControllerAdvice
。 ExceptionHandlerExceptionResolver
将从上下文中检索这些内容,并使用 AnnotationAwareOrderComparator
对它们进行排序,然后,它将为每个
ExceptionHandlerMethodResolver
实例注册一个 ControllerAdviceBean
(将可用的@ExceptionHandler
方法映射到它们打算处理的异常类型)。最后,将它们以相同顺序添加到LinkedHashMap
(保留迭代顺序)。发生异常时,
ExceptionHandlerExceptionResolver
将遍历这些ExceptionHandlerMethodResolver
并使用可以处理该异常的第一个。因此,这里的要点是:如果您有一个
@ControllerAdvice
的@ExceptionHandler
的Exception
在另一个带有@ControllerAdvice
的@ExceptionHandler
类之前注册了更具体的异常,例如IOException
,则第一个将被调用。如前所述,可以通过让带有@ControllerAdvice
的注释类实现 Ordered
或使用 @Order
或 @Priority
对其进行注释并为其指定适当的值,来控制该注册顺序。