前言
- 这里也许会有更好的阅读体验
- 请大家看完以后一定要吐槽
1. Overview
当请求映射或处理请求时发生异常,DispatcherServlet 会将异常委派给 HandlerExceptionResolver 链来处理,然后响应一个错误信息。
1.1 几个特殊的 Bean
HandlerMapping 接口
- 通过 @RequestMapping 将 Controller 中的方法注册到 DispatcherServlet 的一个 List 中
HandlerExecutionChain
- 通过 HandlerMapping::getHandler 获取
- 包含一个 handler,指定了请求 URL 匹配的 Controller 和方法
- 包含 HandlerInterceptor 串
HandlerInterceptor 接口
- 包含 preHandle、postHandle 和 afterCompletion 三个抽象方法
- 用法有点像 Servlet 的 Filter,但是拦截器是基于 Java 反射,是 AOP 的一种运用,在这里是用来干啥的我也不太清楚
2. 异常处理过程 (POST 请求)
2.1 捕获异常
DispatcherServlet::doDispatch 通过 try / catch 捕获映射和处理请求的过程中抛出的异常
Exception dispatchException = null;
try {
...
// 根据 RequestMapping 找到处理请求的 Bean 和方法
HandlerExecutionChain mappedHandler = getHandler(processedRequest);
// 由 HandlerAdapter 代理执行处理请求的方法
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
...
}
catch (Exception ex) {
// 将异常赋值给 dispatchException
dispatchException = ex;
}
// 处理响应(有无异常都是这个方法来处理)
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
2.2 处理异常
在 processDispatchResult 方法中,DispatcherServlet 是用 HandlerExceptionResolverComposite 来处理异常的。而 HandlerExceptionResolverComposite 又通过一个 HandlerExceptionResolver 链来处理异常:
- ExceptionHandlerExceptionResolver - 根据异常类型匹配注解了 @ExceptionHandler 的方法来处理
- ResponseStatusExceptionResolver - 根据 @ResponseStatus 修改响应中的 HTTP status
- DefaultHandlerExceptionResolver - 根据异常类型返回 HTTP status 和 codes
// this.resolvers 中包含以上三个 HandlerExceptionResolver
for (HandlerExceptionResolver handlerExceptionResolver : this.resolvers) {
ModelAndView mav = handlerExceptionResolver.resolveException(request, response, handler, ex);
if (mav != null) {
return mav;
}
}
2.3 HandlerExceptionResolver 类关系图
![59cd14b808d7137c0ca37949e88071c1.png](https://img-blog.csdnimg.cn/img_convert/59cd14b808d7137c0ca37949e88071c1.png)
- Ordered::getOrder 表示在异常处理链中 HandlerExceptionResolver 的执行顺序
- HandlerExceptionResolverComposite 用了一个 List 来存放其它三个 HandlerExceptionResolver 的实现
通过 HandlerExceptionResolver::resolveException 可以找到各个实现中具体处理异常的方法:
- ExceptionHandlerExceptionResolver::doResolveHandlerMethodException
- ResponseStatusExceptionResolver::doResolveException
- DefaultHandlerExceptionResolver::doResolveException
2.4 拦截器
除了 @ExceptionHandler 和 DefaultHandlerExceptionResolver 中的定义的异常类型,其它的异常不会被 HandlerExceptionResolver 链处理,例如 RuntimeException。
拦截器会将请求重新向到 /error。如果找不到 /error 的话就会返回错误:
{"status": 500, "error": "Internal Server Error", ...}
拦截器这一块具体是怎么重定向到 /error 我就不知道了,没怎么看懂。
参考
- https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html