Spring MVC 默认使用 ExceptionHandlerExceptionResolver 、 ResponseStatusExceptionResolver 以及 DefaultHandlerExceptionResolver 这三种的 HandlerExceptionResolver 对 Spring MVC 中抛出的异常进行集中处理
ExceptionHandlerExceptionResolver
ExceptionHandlerExceptionResolver 默认情况下第一个执行。
ExceptionHandlerExceptionResolver 与 @ExceptionHandler 一起配合来处理异常。也就是说,当 Spring MVC 抛出了一个异常的时候,默认情况下首先会把这个异常交给 ExceptionHandlerExceptionResolver 进行处理,而 ExceptionHandlerExceptionResolver 就会去找是否有能够处理这个异常的 @ExceptionHandler,如果没有的话,就会把异常交给下一个的 HandlerExceptionResolver 进行处理。
其实在 Spring MVC 3.2 之前,默认注册的是 AnnotationMethodHandlerExceptionResolver,而不是 ExceptionHandlerExceptionResolver,但两者都是用来跟 @ExceptionHandler 一起配合使用的。
ResponseStatusExceptionResolver
ResponseStatusExceptionResolver 默认情况下第二个执行。
ResponseStatusExceptionResolver 与 @ResponseStatus 一起配合来处理异常。也就是说,当 Spring MVC 把异常交给 ResponseStatusExceptionResolver 处理的话,它会去查看这个异常是否有使用了 @ResponseStatus ,如果有使用了 @ResponseStatus 的话,就按照 @ResponseStatus 所设置的 code 以及 reason 属性将错误信息发送给客户端,如果这个异常没有使用 @ResponseStatus 的话,就会把异常交给下一个的 HandlerExceptionResolver 进行处理。
DefaultHandlerExceptionResolver
DefaultHandlerExceptionResolver 默认情况下第三个执行。
DefaultHandlerExceptionResolver 使用了一个映射表,这个映射表主要是用来映射 Spring MVC 内部定义的异常与对应的 HTTP 状态码。
如果当前的异常在映射表中有对应的状态码的话,就会以这个状态码来返回给客户端,如果映射表中不存在相对应的状态码的话,就会将这个异常交给下一个的 HandlerExceptionResolver 进行处理。

HandlerExceptionResolverComposite
其实 ExceptionHandlerExceptionResolver 、ResponseStatusExceptionResolver 与 DefaultHandlerExceptionResolver 其实并没有直接在 Spring 中注册,而是间接通过 HandlerExceptionResolverComposite 才得以生效的。
HandlerExceptionResolverComposite 本身就是一个 HandlerExceptionResolver,它在 WebMvcConfigurationSupport (即 @EnableWebMvc 中所 import 的配置类)中被注册成为 bean ,下面是 WebMvcConfigurationSupport 中注册 HandlerExceptionResolverComposite 的源码:
@Bean
public HandlerExceptionResolver handlerExceptionResolver(@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager) {
List<HandlerExceptionResolver> exceptionResolvers = new ArrayList();
this.configureHandlerExceptionResolvers(exceptionResolvers);
if (exceptionResolvers.isEmpty()) {
this.addDefaultHandlerExceptionResolvers(exceptionResolvers, contentNegotiationManager);
}
this.extendHandlerExceptionResolvers(exceptionResolvers);
HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
//将 HandlerExceptionResolverComposite 的执行顺序设成 0 ,所以 HandlerExceptionResolverComposite 将会在所有被注册的 HandlerExceptionResolver 中第一个被执行
composite.setOrder(0);
//三个默认的 HandlerExceptionResolver 就包含在 exceptionResolvers 中
composite.setExceptionResolvers(exceptionResolvers);
return composite;
}上面代码中的 exceptionResolvers 中就包含了 ExceptionHandlerExceptionResolver 、ResponseStatusExceptionResolver 以及 DefaultHandlerExceptionResolver 这三个默认的 HandlerExceptionResolver 。然后当 HandlerExceptionResolverComposite 执行的时候,就会去遍历这个 exceptionResolvers ,按照 ExceptionHandlerExceptionResolver ->ResponseStatusExceptionResolver ->DefaultHandlerExceptionResolver 的顺序依次取出去处理异常:
@Nullable
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
if (this.resolvers != null) {
Iterator var5 = this.resolvers.iterator();
while(var5.hasNext()) {
HandlerExceptionResolver handlerExceptionResolver = (HandlerExceptionResolver)var5.next();
ModelAndView mav = handlerExceptionResolver.resolveException(request, response, handler, ex);
if (mav != null) {
return mav;
}
}
}
return null;
}当 HandlerExceptionResolverComposite 在遍历了所有三个默认的 HandlerExceptionResolver 之后,resolveException 的返回值还是为 null 的话,就会将异常交给其他自定义的 HandlerExceptionResolver 去处理。
如何设置自定义的 HandlerExceptionResolver 与 HandlerExceptionResolverComposite 之间的执行顺序
HandlerExceptionResolverComposite 实现了 Ordered 接口,而一般来说我们自定义 HandlerExceptionResovler 的时候是去继承 AbstractHandlerExceptionResolver 类,而 AbstractHandlerExceptionResolver 同样也实现了 Ordered 接口,所以说我们可以通过设置 Ordered 接口的 getOrder() 方法的返回值的方式来改变 HanderExceptionResolver 之间的执行顺序。
因为 HandlerExceptionResolverComposite 在注册时候将 order 的值设置为了 0,所以说,如果我们想让自定义的 HandlerExceptionResovler 在 HandlerExceptionResolverComposite 执行之前就执行的话,就可以将 getOrder() 的返回值设置为小于 0 的值(可以是负数):
public class TestHandlerExceptionResolver extends AbstractHandlerExceptionResolver {
@Override
public int getOrder() {
//返回值为 -1,比 0 小,所以会比 HandlerExceptionResolverComposite 先执行
return -1;
}
@Override
protected ModelAndView doResolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
return null;
}
}