springmvc揭秘异常处理机制

HandlerExceptionResolver异常处理

HandlerExceptionResolver是专门进行异常处理的,在render之前进行工作,从异常中解析出ModelAndView

复制代码
public interface HandlerExceptionResolver {
  
   ModelAndView resolveException(
         HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);

}
  • DefaultHandlerExceptionResolver 根据不同类型的异常来进行解析,response.sendError设置不同的错误码

    复制代码
    response.sendError(HttpServletResponse.SC_NOT_FOUND);
  • ExceptionHandlerExceptionResolver 使用@ExceptionHandler注解的方法来进行异常解析

  • ResponseStatusExceptionResolver 解析有@ResponseStatus注解的异常

  • SimpleMappingExceptionResolver 通过配置的异常类和View的映射关系来解析异常

ExceptionHandlerExceptionResolver

我一般都是使用@ExceptionHandler注解,所以就以ExceptionHandlerExceptionResolver为例

所有的HandlerExceptionResolver实现类都是去重写resolveException方法

复制代码
// org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver#resolveException
@Override
public ModelAndView resolveException(
      HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
  // 判断当前HandlerExceptionResolver是否可以解析
   if (shouldApplyTo(request, handler)) {
     // 判断是否禁用缓存,如果禁用缓存的话,设置响应头
      prepareResponse(ex, response);
     // 具体的处理逻辑
      ModelAndView result = doResolveException(request, response, handler, ex);
      if (result != null) {
         
         // Explicitly configured warn logger in logException method.
         logException(ex, request);
      }
      return result;
   }
   else {
      return null;
   }
}
shouldApplyTo
复制代码
// org.springframework.web.servlet.handler.AbstractHandlerMethodExceptionResolver#shouldApplyTo
@Override
protected boolean shouldApplyTo(HttpServletRequest request, Object handler) {
   if (handler == null) {
      return super.shouldApplyTo(request, handler);
   }
   else if (handler instanceof HandlerMethod) {
      HandlerMethod handlerMethod = (HandlerMethod) handler;
      handler = handlerMethod.getBean();
      return super.shouldApplyTo(request, handler);
   }
   else {
      return false;
   }
}

// org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver#shouldApplyTo
protected boolean shouldApplyTo(HttpServletRequest request, Object handler) {
  if (handler != null) {
      // mappedHandlers是处理器的集合
      if (this.mappedHandlers != null && this.mappedHandlers.contains(handler)) {
    return true;
   }
      // mappedHandlerClasses是处理器类型的集合
   if (this.mappedHandlerClasses != null) {
    for (Class<?> handlerClass : this.mappedHandlerClasses) {
     if (handlerClass.isInstance(handler)) {
      return true;
     }
    }
   }
  }
  // Else only apply if there are no explicit handler mappings.
  return (this.mappedHandlers == null && this.mappedHandlerClasses == null);
 }
doResolveException

该方法是处理异常的实际方法

复制代码
protected final ModelAndView doResolveException(
      HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {

   return doResolveHandlerMethodException(request, response, (HandlerMethod) handler, ex);
}

protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request,
   HttpServletResponse response, HandlerMethod handlerMethod, Exception exception) {
  // 找到处理异常的方法
  ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);
  if (exceptionHandlerMethod == null) {
   return null;
  }
  // 设置argumentResolvers和returnValueHandlers
  exceptionHandlerMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
  exceptionHandlerMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);

  ServletWebRequest webRequest = new ServletWebRequest(request, response);
  ModelAndViewContainer mavContainer = new ModelAndViewContainer();

  try {
   
   Throwable cause = exception.getCause();
   if (cause != null) {
    // Expose cause as provided argument as well
        // 执行exceptionHandler方法解析异常
    exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception, cause, handlerMethod);
   }
   else {
    // Otherwise, just the given exception as-is
    exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception, handlerMethod);
   }
  }
  catch (Throwable invocationEx) {
   
   // Continue with default processing of the original exception...
   return null;
  }

  if (mavContainer.isRequestHandled()) {
   return new ModelAndView();
  }
  else {
   ModelMap model = mavContainer.getModel();
   HttpStatus status = mavContainer.getStatus();
   ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, status);
   mav.setViewName(mavContainer.getViewName());
   if (!mavContainer.isViewReference()) {
    mav.setView((View) mavContainer.getView());
   }
   if (model instanceof RedirectAttributes) {
    Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
    RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
   }
   return mav;
  }
 }

https://zhhll.icu/2021/框架/springmvc/底层剖析/5.HandlerExceptionResolver/

本文由mdnice多平台发布

相关推荐
今天的砖头有点烫手啊4 分钟前
Java IO/NIO/AIO 演进:从 BIO 到 Netty 的底层逻辑
java·jvm·nio
谢亮_vipxieliang41 分钟前
Java 21 新特性实战:Record、Sealed、模式匹配
java·开发语言
霸道流氓气质1 小时前
LLM 应用限流与熔断机制完全指南:从多层防护架构到Java生产级弹性实战
java·开发语言·架构
不会就选b1 小时前
算法日常・每日刷题--<动态规划>1
java·数据结构·算法
晚安code1 小时前
JVM 内存结构入门:程序计数器、虚拟机栈、本地方法栈与堆的溢出诊断
java·jvm
自强的小白1 小时前
Spring事务失效的场景
java·spring
小蒜学长1 小时前
基于SpringBoot+Vue的小学数学智能出题系统(代码+数据库+LW)
java·数据库·spring boot·后端·智能出题系统
不灭的黄金瞳1232 小时前
Java继承与多态
java·intellij-idea
企业数字化笔记2 小时前
视频字幕如何烧录到成片?硬字幕、软字幕、样式控制与播放验收
java·ffmpeg
小朱爱编程1232 小时前
我用 Jev 做了三个实用工具:整理标签页、分诊飞书反馈、找回 GitHub 收藏
java·开发语言·人工智能·后端·python·架构·ai编程