SpringMVC异常处理流程总结
一、异常处理方式一:@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解析错误视图主要的流程是:
- resolveErrorView方法首先得到错误的http状态码,并根据状态码名称调用resolve方法:
- resolve方法去/templates/error下面寻找名称与状态码对应的模板,如404.html,如果有就会将其渲染成视图,返回ModelAndView对象;
- 如果没有,再调用resolveResource去静态资源目录下寻找: “classpath:/META-INF/resources/”, “classpath:/resources/”, “classpath:/static/”, “classpath:/public/”
- 若仍然没有,resolve方法最终返回ModelAndView为null;
- 当ModelAndView为null,再去验证错误代码是否是4xx或5xx,然后再按照上面resolve方法的逻辑去找是否有4xx.html或5xx.html;
- 如果仍然没找到,返回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默认的错误白页。
总结:异常请求处理流程
其实方式一和方式二都属于异常请求处理流程的一部分,方式一无法处理的异常就会由方式二进行处理。异常请求处理的流程主要分成五步:
- 解析错误请求抛出异常
- 尝试处理错误请求(方式一处理)
- 如果处理失败,会给底层response发送错误信息;然后再重新发送一个/error请求
- /error请求被ErrorController处理(方式二处理)
- 若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异常处理流程总结相关推荐
- SpringMVC异常处理流程
2019独角兽企业重金招聘Python工程师标准>>> Controller中的方法执行出现异常ex. ex在DispatchServlet中被捕获,交给默认的ExceptionHa ...
- SpringMVC运行流程分析
一.运行流程图 下面是 SpringMVC 运行流程的分析图,包括了拦截器的调用过程,目标资源的处理以及异常处理. 二.运行流程中的相关组件 在上面的流程图中有几个比较重要的组件,下面大概描述一下其对 ...
- 【 第六章 拦截器,注解配置springMVC,springMVC执行流程】
第六章 拦截器,注解配置springMVC,springMVC执行流程 1.拦截器: ①springMVC中的拦截器用于拦截控制器方法的执行. ②springMVC的拦截器需要实现HandlerInt ...
- SpringMVC 异常处理(简单异常处理器 SimpleMappingExceptionResolver;自定义异常处理需要实现HandlerExceptionResolver接口)
一.SpringMVC 框架异常处理流程 二.异常处理的两种方式 三.简单异常处理器 SimpleMappingExceptionResolver 1.自定义异常类 package com.lt.ex ...
- SpringMVC异常处理机制详解[附带源码分析]
SpringMVC异常处理机制详解[附带源码分析] 参考文章: (1)SpringMVC异常处理机制详解[附带源码分析] (2)https://www.cnblogs.com/fangjian0423 ...
- ipqc异常处理流程图_产线异常处理流程
与<产线异常处理流程>相关的范文 供应商来料异常管理流程 1. 目的: 规范来料产品的异常处理流程控制,提高来料合格率. 2. 范围: 本规范适用于所有外购零部件及外包加工件. 3. 职责 ...
- Windows异常学习笔记(二)—— 内核异常处理流程用户异常的分发
Windows异常学习笔记(二)-- 内核异常处理流程&用户异常分发 用户层与内核层异常 内核异常 分析 KiDispatchException 分析 RtlDispatchException ...
- springmvc执行流程(简述易懂)
Spring MVC框架的控制器 控制器的主要作用就是处理特定URL发过来的HTTP请求,然后进行业务逻辑处理,将结果返回给某个特定的视图. springmvc执行流程 1:客户端请求提交到Dispa ...
- springMVC请求流程详解
SpringMVC框架是一个基于请求驱动的Web框架,并且使用了'前端控制器'模型来进行设计, 再根据'请求映射规则'分发给相应的页面控制器进行处理.核心流程: 第一步:发起请求到前端控制器(Disp ...
最新文章
- android route命令详解,route cmd命令详解
- Target runtime Apache Tomcat 6.0 is not defined
- 北美公司面试经验笔记
- 求两个Linux文本文件的交集、差集、并集
- 拜托!面试请不要再问我 Spring Cloud 底层原理 ...
- Leetcode:5.longest-palindromic-substring(最长回文子串)
- Dojo1.6新特性概览
- python2最新版本_Python 2.7.18发布,Python 2的最新版本
- 红帽linux系统安装指导
- 斐讯k2路由器刷第三方固件
- Android usb网卡配置ip地址,安卓手机通过电脑USB上网设置教程
- redhat 8常用命令实践
- 崔羚:乳品行业后道包装及物流解决方案
- qgraphicsitem 复制副本,QGraphicsItem:调用paint函数时
- 猿创征文|收到谷歌开发者大会正式邀请(Java学生的自学之路)
- 发布网站 IIS部署网站
- 腾讯面试题:买200返100优惠券,实际上折扣是多少?
- RabbitMQ学习笔记(高级篇)
- MacOS Ventura 13.2.1 (22D68) 正式版带 OC 0.8.9 and winPE 双分区原版黑苹果镜像
- 【阅读笔记】TypeScript菜鸟教程