该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读
Spring 版本:5.2.4.RELEASE
该系列其他文档请查看:《精尽 Spring MVC 源码分析 - 文章导读》
HandlerExceptionResolver 组件HandlerExceptionResolver 组件,处理器异常解析器,将处理器( handler )执行时发生的异常(也就是处理请求,执行方法的过程中)解析(转换)成对应的 ModelAndView 结果
回顾先来回顾一下在 DispatcherServlet 中处理请求的过程中哪里使用到 HandlerExceptionResolver 组件,可以回到《一个请求的旅行过程》中的 DispatcherServlet 的 processHandlerException 方法中看看,如下:
@Nullable protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) throws Exception { // Success and error responses may use different content types // 移除 PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE 属性 request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE); // Check registered HandlerExceptionResolvers... // <a> 遍历 HandlerExceptionResolver 数组,解析异常,生成 ModelAndView 对象 ModelAndView exMv = null; if (this.handlerExceptionResolvers != null) { // 遍历 HandlerExceptionResolver 数组 for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) { // 解析异常,生成 ModelAndView 对象 exMv = resolver.resolveException(request, response, handler, ex); // 生成成功,结束循环 if (exMv != null) { break; } } } // <b> 情况一,生成了 ModelAndView 对象,进行返回 if (exMv != null) { // ModelAndView 对象为空,则返回 null if (exMv.isEmpty()) { request.setAttribute(EXCEPTION_ATTRIBUTE, ex); return null; } // We might still need view name translation for a plain error model... // 没有视图则设置默认视图 if (!exMv.hasView()) { String defaultViewName = getDefaultViewName(request); if (defaultViewName != null) { exMv.setViewName(defaultViewName); } } // 设置请求中的错误消息属性 WebUtils.exposeErrorRequestAttributes(request, ex, getServletName()); return exMv; } // <c> 情况二,未生成 ModelAndView 对象,则抛出异常 throw ex; }在 Spring MVC 的 DispatcherServlet 处理请求执行方法过程中,不管是否抛出异常都会进行结果处理,如果抛出了异常也需要调用该方法处理异常
可以看到,在 <a> 处会遍历所有的 HandlerExceptionResolver 异常处理器来处理,如果某一个处理器处理成功并返回 ModelAndView 对象,则直接返回
HandlerExceptionResolver 接口org.springframework.web.servlet.HandlerExceptionResolver,异常处理器接口,代码如下:
public interface HandlerExceptionResolver { /** * 解析异常,转换成对应的 ModelAndView 结果 */ @Nullable ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex); }HandlerExceptionResolver 接口体系的结构如下:
初始化过程在 DispatcherServlet 的 initHandlerExceptionResolvers(ApplicationContext context) 方法,初始化 HandlerExceptionResolver 组件,方法如下:
private void initHandlerExceptionResolvers(ApplicationContext context) { // 置空 handlerExceptionResolvers 处理 this.handlerExceptionResolvers = null; // 情况一,自动扫描 HandlerExceptionResolver 类型的 Bean 们 if (this.detectAllHandlerExceptionResolvers) { // Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts. Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils .beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values()); // We keep HandlerExceptionResolvers in sorted order. AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers); } } // 情况二,获得名字为 HANDLER_EXCEPTION_RESOLVER_BEAN_NAME 的 Bean else { try { HandlerExceptionResolver her = context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class); this.handlerExceptionResolvers = Collections.singletonList(her); } catch (NoSuchBeanDefinitionException ex) { // Ignore, no HandlerExceptionResolver is fine too. } } // Ensure we have at least some HandlerExceptionResolvers, by registering // default HandlerExceptionResolvers if no other resolvers are found. /** * 情况三,如果未获得到,则获得默认配置的 HandlerExceptionResolver 类 * {@link org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver} * {@link org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver} * {@link org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver} */ if (this.handlerExceptionResolvers == null) { this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class); if (logger.isTraceEnabled()) { logger.trace("No HandlerExceptionResolvers declared in servlet '" + getServletName() + "': using default strategies from DispatcherServlet.properties"); } } }
如果“开启”探测功能,则扫描已注册的 HandlerExceptionResolver 的 Bean 们,添加到 handlerExceptionResolvers 中,默认开启
如果“关闭”探测功能,则获得 Bean 名称为 "handlerExceptionResolver" 对应的 Bean ,将其添加至 handlerExceptionResolvers