一、异常处理方式一:@ControllerAdvice+@ExceptionHandler

(1)使用方法

通过@ControllerAdvice+@Exception的方式便可以指定在请求处理的整个流程中如果出现了@ExceptionHandler注解中指定的这些异常,便可以通过该@ExceptionHandler所标注的方法来处理该类异常,该类中的方法同常规的Controller中的方法一致,如果返回String便会找到相对应的页面进行渲染,如果类上标注了@RestControllerAdvice返回类型为String则会返回JSON字符串。

@ControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler({ArithmeticException.class, NullPointerException.class})public String handleException() {return "error";}}

(2)原理分析

SpringMVC的核心组件是DispatcherServlet,而DispatcherServlet的核心处理流程全部在doDispatch方法中,而在这个方法的所有核心步骤中只要抛出了异常都会封装到Exception类型的dispatchException这个变量中,并将该对象传入到processDispatchResult方法中。该方法中会判断是否有异常传入,有异常传入则会调用processHandlerException方法来获取视图,processHandlerException会遍历所有实现了HandlerExceptionResolver接口类的resolveException方法看有没有一个类可以处理该异常。

总结一下:doDispatch方法的核心流程中抛出异常→catch住异常存入dispatchException变量→调用processDispatchResult→调用processHandlerException→遍历所有实现了HandlerExceptionResolver接口类看能否处理当前异常→能处理返回视图进行渲染

关键组件:HandlerExceptionResolver接口

上图是在controller中抛出除0异常后遍历handlerExceptionResolvers集合时debug观察到的集合中的元素,其中DefaultErrorAttributes虽然实现了HandlerExceptionResolver接口但并不处理任何异常,只负责把异常对象存入request域中。而后三个resolver是在DispatcherServlet初始化时存入的,这三个resovler写在了DispatcherServlet.properties中。

org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

其中的ExceptionHandlerExceptionResolver负责在标注了@ControllerAdvice的类中找标注了@ExceptionHandler并且标注了当前异常类的方法进行处理,处理后返回视图进行渲染。

顺带说一下ResponseStatusExceptionResolver这个resovler个人认为实际生产中用的较少就不分析了,而DefaultHandlerExceptionResolver负责处理Spring自己抛出的异常,比如下面这种异常,如果客户端请求/demo/hello时没有带参数a,则会抛出org.springframework.web.bind.MissingServletRequestParameterException异常,该异常是Spring内部异常所以由DefaultHandlerExceptionResolver进行处理。

@RestController
@RequestMapping("/demo")
public class DemoController {@RequestMapping("/hello")public String hello(@RequestParam("a") int a) {return "hello";}}

二、异常处理方式二:BasicErrorController+ErrorViewResolver

(1)使用方法

我们使用这种处理方式处理异常其实只需要在/template/error下或者静态资源目录下(​ “classpath:/META-INF/resources/”, “classpath:/resources/”, “classpath:/static/”, “classpath:/public/”)定义对应错误码的页面(如404.html)或者4xx.html、5xx.html页面。

(2)原理分析

经过方式一不能处理的异常会通过发送/error请求再次来到DispatcherServlet的核心流程,Springboot为我们注册了BasicErrorController来专门处理/error请求,BasicErrorController内部的处理过程则是通过ErrorViewResolver解析对应的错误码并返回ModelAndView,同样的Springboot也为我们注册了DefaultErrorViewResolver来解析错误码返回ModelAndView。

BasicErrorController处理流程:

@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {//略...@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {HttpStatus status = getStatus(request);Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML)));response.setStatus(status.value());ModelAndView modelAndView = resolveErrorView(request, response, status, model);return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);}//略...
}
 protected ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response, HttpStatus status,Map<String, Object> model) {for (ErrorViewResolver resolver : this.errorViewResolvers) {ModelAndView modelAndView = resolver.resolveErrorView(request, status, model);if (modelAndView != null) {return modelAndView;}}return null;}

DefaultErrorViewResolver解析错误视图主要的流程是:

  1. resolveErrorView方法首先得到错误的http状态码,并根据状态码名称调用resolve方法:

    1. resolve方法去/templates/error下面寻找名称与状态码对应的模板,如404.html,如果有就会将其渲染成视图,返回ModelAndView对象;
    2. 如果没有,再调用resolveResource去静态资源目录下寻找:​ “classpath:/META-INF/resources/”, “classpath:/resources/”, “classpath:/static/”, “classpath:/public/”
    3. 若仍然没有,resolve方法最终返回ModelAndView为null;
  2. 当ModelAndView为null,再去验证错误代码是否是4xx或5xx,然后再按照上面resolve方法的逻辑去找是否有4xx.html或5xx.html;
  3. 如果仍然没找到,返回null;

代码如下:

public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {//略...@Overridepublic ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {ModelAndView modelAndView = resolve(String.valueOf(status.value()), model);if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);}return modelAndView;}//略...
}

如果我们对DefaultErrorViewResolver处理对应错误码的方式不满意,则可以通过自定义ErrorViewResolver接口的实现类加入到容器中来替换DefaultErrorViewResolver的默认行为。如果我们对BasicErrorController的处理方式不满意,比如我们想直接返回Json字符串,则可以通过自定义ErrorController接口的实现类加入到容器中来替换BasicErrorController

如果通过DefaultErrorViewResovler仍不能处理当前错误码的/error请求,则会返回视图名为error的ModelAndView,该视图error最终会被BeanNameViewResolver这个视图解析器解析得到一个bean名称为error的View对象,调用该对象的渲染方法,最终为我们呈现出来的就是Springboot默认的错误白页。  

总结:异常请求处理流程

其实方式一和方式二都属于异常请求处理流程的一部分,方式一无法处理的异常就会由方式二进行处理。异常请求处理的流程主要分成五步:

  1. 解析错误请求抛出异常
  2. 尝试处理错误请求(方式一处理)
  3. 如果处理失败,会给底层response发送错误信息;然后再重新发送一个/error请求
  4. /error请求被ErrorController处理(方式二处理)
  5. 若ErrorController中的ErrorViewResolver仍不能处理返回视图,则new一个视图名为error的ModelAndView对象,最终该视图会由Springboot自动装配的BeanNameViewResolver解析得到一个bean名称为error的View对象,该View对象进行渲染后即得到Springboot的默认错误白页

附:Springboot自动装配的异常处理组件

上述的许多组件都不是我们自己装入容器的,这些组件是由Springboot为我们自动装入的。Springboot在其自动配置包spring-boot-autoconfigure中的ErrorMvcAutoConfiguration类中主要为我们自动装配了包括DefaultErrorAttributes、BasicErrorController、DefaultErrorViewResolver、View(bean名称为error)、BeanNameViewResolver、

这里声明下,本文的异常处理流程是在Springboot搭建的SSM项目环境下,如果是原生的Web.xml搭建的SSM项目则没有Springboot装配的这些组件,如果需要这些组件提供的功能需要自动手动进行导入到容器中。

参考博客

常请求处理流程 发送/error请求以及得到error视图的详细原理_bejsoiv的博客-CSDN博客

SpringMVC异常处理流程总结相关推荐

  1. SpringMVC异常处理流程

    2019独角兽企业重金招聘Python工程师标准>>> Controller中的方法执行出现异常ex. ex在DispatchServlet中被捕获,交给默认的ExceptionHa ...

  2. SpringMVC运行流程分析

    一.运行流程图 下面是 SpringMVC 运行流程的分析图,包括了拦截器的调用过程,目标资源的处理以及异常处理. 二.运行流程中的相关组件 在上面的流程图中有几个比较重要的组件,下面大概描述一下其对 ...

  3. 【 第六章 拦截器,注解配置springMVC,springMVC执行流程】

    第六章 拦截器,注解配置springMVC,springMVC执行流程 1.拦截器: ①springMVC中的拦截器用于拦截控制器方法的执行. ②springMVC的拦截器需要实现HandlerInt ...

  4. SpringMVC 异常处理(简单异常处理器 SimpleMappingExceptionResolver;自定义异常处理需要实现HandlerExceptionResolver接口)

    一.SpringMVC 框架异常处理流程 二.异常处理的两种方式 三.简单异常处理器 SimpleMappingExceptionResolver 1.自定义异常类 package com.lt.ex ...

  5. SpringMVC异常处理机制详解[附带源码分析]

    SpringMVC异常处理机制详解[附带源码分析] 参考文章: (1)SpringMVC异常处理机制详解[附带源码分析] (2)https://www.cnblogs.com/fangjian0423 ...

  6. ipqc异常处理流程图_产线异常处理流程

    与<产线异常处理流程>相关的范文 供应商来料异常管理流程 1. 目的: 规范来料产品的异常处理流程控制,提高来料合格率. 2. 范围: 本规范适用于所有外购零部件及外包加工件. 3. 职责 ...

  7. Windows异常学习笔记(二)—— 内核异常处理流程用户异常的分发

    Windows异常学习笔记(二)-- 内核异常处理流程&用户异常分发 用户层与内核层异常 内核异常 分析 KiDispatchException 分析 RtlDispatchException ...

  8. springmvc执行流程(简述易懂)

    Spring MVC框架的控制器 控制器的主要作用就是处理特定URL发过来的HTTP请求,然后进行业务逻辑处理,将结果返回给某个特定的视图. springmvc执行流程 1:客户端请求提交到Dispa ...

  9. springMVC请求流程详解

    SpringMVC框架是一个基于请求驱动的Web框架,并且使用了'前端控制器'模型来进行设计, 再根据'请求映射规则'分发给相应的页面控制器进行处理.核心流程: 第一步:发起请求到前端控制器(Disp ...

最新文章

  1. android route命令详解,route cmd命令详解
  2. Target runtime Apache Tomcat 6.0 is not defined
  3. 北美公司面试经验笔记
  4. 求两个Linux文本文件的交集、差集、并集
  5. 拜托!面试请不要再问我 Spring Cloud 底层原理 ...
  6. Leetcode:5.longest-palindromic-substring(最长回文子串)
  7. Dojo1.6新特性概览
  8. python2最新版本_Python 2.7.18发布,Python 2的最新版本
  9. 红帽linux系统安装指导
  10. 斐讯k2路由器刷第三方固件
  11. Android usb网卡配置ip地址,安卓手机通过电脑USB上网设置教程
  12. redhat 8常用命令实践
  13. 崔羚:乳品行业后道包装及物流解决方案
  14. qgraphicsitem 复制副本,QGraphicsItem:调用paint函数时
  15. 猿创征文|收到谷歌开发者大会正式邀请(Java学生的自学之路)
  16. 发布网站 IIS部署网站
  17. 腾讯面试题:买200返100优惠券,实际上折扣是多少?
  18. RabbitMQ学习笔记(高级篇)
  19. MacOS Ventura 13.2.1 (22D68) 正式版带 OC 0.8.9 and winPE 双分区原版黑苹果镜像
  20. 【阅读笔记】TypeScript菜鸟教程

热门文章

  1. DOM4J读取和写入XML文件
  2. Matlab中rectangle函数使用
  3. Pytorch中的torch.gather函数的含义
  4. pytorch中的gather()函数
  5. Java中的日志分类及应用
  6. HTML 七牛上传图片
  7. dat模板文件读取的Python脚本
  8. CESS 受邀出席杜克大学举办的 Web3 大会 DW3C
  9. 【时空点滴系列之1】大公司都喜欢的猥琐动作:尾随时髦小网子。
  10. altium 原理图reset unique id