我有多个用
@ControllerAdvice
注释的类,每个类都有一个
@ExceptionHandler
方法。
一个处理
Exception
的意图是,如果找不到更具体的处理程序,就应该使用它。
遗憾的是,Spring似乎总是使用最通用的案例(
Exception
),而不是更具体的案例(例如,
IOException
)。
这就是人们期望Spring行为的方式吗?我正在尝试模拟泽西的模式,该模式评估每个
ExceptionMapper
(等效组件),以确定它处理的声明类型与抛出的异常有多远,并且总是使用最近的祖先。
发布于 2013-10-21 17:18:55
这就是人们期望Spring行为的方式吗?
从Spring4.3.7开始,以下是Spring的行为方式:它使用
HandlerExceptionResolver
实例来处理处理程序方法引发的异常。
默认情况下,web配置注册一个
HandlerExceptionResolver
bean,
HandlerExceptionResolverComposite
,它
委托给其他
HandlerExceptionResolvers
的列表。
其他的解析器是
ExceptionHandlerExceptionResolver
ResponseStatusExceptionResolver
DefaultHandlerExceptionResolver
按该顺序登记。就这个问题而言,我们只关心
ExceptionHandlerExceptionResolver
。
通过
AbstractHandlerMethodExceptionResolver
方法解析异常的@ExceptionHandler
。
在上下文初始化时,Spring将为它检测到的每个
@ControllerAdvice
注释类生成一个
@ControllerAdvice
。
ExceptionHandlerExceptionResolver
将从上下文中检索它们,并使用以下
AnnotationAwareOrderComparator
对它们进行排序:
是
OrderComparator
的扩展,它支持Spring的Ordered
接口以及@Order
和@Priority
注释,其中order值由order实例提供,覆盖静态定义的注释值(如果有的话)。
然后为每个
ControllerAdviceBean
实例注册一个
ControllerAdviceBean
(将可用的
@ExceptionHandler
方法映射到它们要处理的异常类型)。最后,它们以相同的顺序添加到
LinkedHashMap
(保留迭代顺序)中。
当出现异常时,
ExceptionHandlerExceptionResolver
将遍历这些
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