SpringMVC异常处理机制
SpringMVC异常处理机制
springMVC会将所有在doDispatch方法中的异常捕获,然后处理。无法处理的异常会抛出给容器处理。
在doDispatch()中调用processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException)处理结果:包括出现和不出现异常的处理都放在这里面
下面是它的源码
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();//若抛出的异常是人为的指定mv的,则直接执行
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
"': assuming HandlerAdapter completed request handling");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
如果有异常出现,首先判断是不是ModelAndViewDefiningException,这个异常是认为的定义的,指定了modelAndView,所以直接拿到该mv,执行就行。
如果不是ModelAndViewDefiningException,则要调用processHandlerException(request, response, handler, exception);方法处理。具体源码如下:
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
// Check registered HandlerExceptionResolvers...
ModelAndView exMv = null;
for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
if (exMv != null) {
break;
}
}
if (exMv != 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()) {
exMv.setViewName(getDefaultViewName(request));
}
if (logger.isDebugEnabled()) {
logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex);
}
WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
return exMv;
}
throw ex;
}
该方法会遍历所有的handlerExceptionResolvers,判断能否处理该异常。调用各自的resolveException 方法(一般抛出的异常都需要通过这一步,要么能被处理;要么处理不了,向上抛)。
则现在需要关注这些handlerExceptionResolvers是如何得到的,有什么分类呢?具体参考http://www.cnblogs.com/fangjian0423/p/springMVC-exception-analysis.html#ExceptionHandlerExceptionResolver
1,handlerExceptionResolver的结构如下图所示

2,类的分析
根据上述结构,对SpringMVC异常处理类进行分析:
l SimpleMappingException:根据配置进行解析异常的类,包括配置异常类型,默认的错误视图,默认的响应码,异常映射等配置属性。
使用时只需要在xml配置文件中配置一下就可以
l < mvc:annotation-driven />配置中定义的HandlerExceptionResolver实现类,我们看下< mvc:annotation-driven />配置解析类org.springframework.web.servlet.config
.AnnotationDrivenBeanDefinitionParser中部分代码片段:

可以看到,当我们定义< mvc:annotation-driven >时,框架会自动将三个类ExceptionHandlerExceptionResolver,ResponseStatusExceptionResolver,DefaultHandlerExceptionResolver添加到DispatcherServlet中的handlerExceptionResolvers集合中。并且order分别为1,2,3,ExceptionHandlerExceptionResolver优先级最高,ResponseStatusExceptionResolver第二,DefaultHandlerExceptionResolver第三。
下面分别解析这三个类以及如何使用
(1)ExceptionHandlerExceptionResolver
ExceptionHandlerExceptionResolver处理过程总结一下:根据用户调用Controller中相应的方法得到HandlerMethod,之后构造ExceptionHandlerMethodResolver,构造ExceptionHandlerMethodResolver有2种选择,1.通过HandlerMethod拿到Controller,找出Controller中带有@ExceptionHandler注解的方法(局部) 2.找到@ControllerAdvice注解配置的类中的@ExceptionHandler注解的方法(全局)。这2种方式构造的ExceptionHandlerMethodResolver中都有1个key为Throwable,value为Method的缓存。之后通过发生的异常找出对应的Method,然后调用这个方法进行处理。这里异常还有个优先级的问题,比如发生的是NullPointerException,但是声明的异常有Throwable和Exception,这时候ExceptionHandlerMethodResolver找Method的时候会根据异常的最近继承关系找到继承深度最浅的那个异常,即Exception。
一般使用的时候通过第二种方法,定义一个类并配上注解@ControllerAdvice。然后再该类中定义处理异常的方法并使用注解@ExceptionHandler
(2)ResponseStatusExceptionResolver
该类的doResolveException方法主要在异常及异常父类中找到@ResponseStatus注解,然后使用这个注解的属性进行处理。
一般使用的时候,定义一个异常的时候,带上@ResponseStatus注解,并设置响应状态码。
(3)DefaultHandlerExceptionResolver
该类的doResolveException方法中主要对一些特殊的异常进行处理,比如NoSuchRequestHandlingMethodException、HttpRequestMethodNotSupportedException、HttpMediaTypeNotSupportedException、HttpMediaTypeNotAcceptableException等。
l 自定义异常处理器
实现HandlerExceptionReslover或继承AbstractHandlerExceptionResolver,将自定义的处理器配置到xml文件中,设置order。
3,使用
l SimpleMappingException
在spring-mvc.xml中定义
可以设置order,defaultErrorView,exceptionAttribute,exceptionMappings
如下所示
<bean
class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 配置order为-1,表示优先级最高 -->
<property name="order" value="-1" />
<!-- 定义默认的异常处理页面,当该异常类型的注册时使用 -->
<property name="defaultErrorView" value="error"></property>
<!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception -->
<property name="exceptionAttribute" value="ex"></property>
<!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常也页名作为值 -->
<property name="exceptionMappings">
<props>
<prop key="yellow.exception.BusinessException">error-business</prop>
<prop key="yellow.exception.ParameterException">error-parameter</prop>
<!-- 这里还可以继续扩展对不同异常类型的处理 -->
</props>
</property>
</bean>
l 使用@ControllerAdvice,@ExceptionHandler,@ResponseStatuts
@ControllerAdvice
public class AControllerAdvice {
@ExceptionHandler(BusinessException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public String handleException1() {
return "1,处理Business异常";
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public String handleException() {
return "2,处理一般异常";
}
}
当出现BusinessException时,结果如下

可以发现,返回了400 bad request状态码,表示@ResponseStatus设置生效了。
l 自定义异常处理器:由于第二种方法已经很好的满足了处理异常的需求,一般项目中就不会自定义的处理器了。使用也很简单,只需覆盖doResolveException方法就可以了。
如下所示:如果想返回json,可以使用return new ModelAndView(new FastJsonJsonView(), map);来实现。
public class MyExceptionHandlerWithOrder extends AbstractHandlerExceptionResolver {
@Override
protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) {
// TODO Auto-generated method stub
Map<String, Object> map = new HashMap<String, Object>();
map.put("type", ex.getClass().getName());
map.put("message", ex.getMessage());
return new ModelAndView(new FastJsonJsonView(), map);
}
}
SpringMVC异常处理机制的更多相关文章
- SpringMVC异常处理机制详解[附带源码分析]
目录 前言 重要接口和类介绍 HandlerExceptionResolver接口 AbstractHandlerExceptionResolver抽象类 AbstractHandlerMethodE ...
- springMVC源码分析--异常处理机制HandlerExceptionResolver执行原理(二)
上一篇博客springMVC源码分析--异常处理机制HandlerExceptionResolver简单示例(一)中我们简单地实现了一个异常处理实例,接下来我们要介绍一下HandlerExceptio ...
- 分享知识-快乐自己:Spring中的(三种)异常处理机制
案例目录结构: Web.xml 配置: <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application ...
- springmvc异常处理解析#ExceptionHandlerExceptionResolver
开头 试想一下我们一般怎么统一处理异常呢,答:切面.但抛开切面不讲,如果对每一个controller方法抛出的异常做专门处理,那么着实太费劲了,有没有更好的方法呢?当然有,就是本篇文章接下来要介绍的s ...
- Java异常处理机制 try-catch-finally 剖析
Java拥有着强大的异常处理机制,最近初步学习了下,感觉内容还是挺多的,特此来将自己的理解写出来与大家分享. 一. 在Java代码code中,由于使用Myeclipse IDE,可以自动提醒用户哪里有 ...
- JAVA 异常处理机制
主要讲述几点: 一.异常的简介 二.异常处理流程 三.运行时异常和非运行时异常 四.throws和throw关键字 一.异常简介 异常处理是在程序运行之中出现的情况,例如除数为零.异常类(Except ...
- 深入理解java异常处理机制
异常指不期而至的各种状况,如:文件找不到.网络连接失败.非法参数等.异常是一个事件,它发生在程序运行期间,干扰了正常的指令流程.Java通 过API中Throwable类的众多子类描述各种不同的 ...
- C++学习笔记27:异常处理机制
一.异常处理机制基础 异常的定义 程序中可以检测的运行不正常的情况 异常处理的基本流程 某段程序代码在执行操作时发生特殊情况,引发一个特定的异常 另一段程序代码捕获该异常并处理它 二.异常的引发 th ...
- C++中的异常处理机制
C++中的捕获异常机制catch参数中实参的类型不同,采取的处理方式则不相同,且与普通的函数调用还不一样,具体表现为当抛出异常throw A()或throw obj时,对象会进行一次额外的对象复制操作 ...
随机推荐
- Delphi Language Overview
Delphi is a high-level, compiled, strongly typed language that supports structured and object-orient ...
- [leetcode] 16. Add Binary
这个题目相对有点奇怪,题目如下: Given two binary strings, return their sum (also a binary string). For example, a = ...
- SQL SERVER 2008 附加数据库出现只读问题。
问题描述 在附加数据库时出现的图片: 解决办法 步骤一,修改文件夹的 1.打开该数据库文件存放的目录或数据库文件的属性窗口,选择"属性"菜单->选择"安全&qu ...
- 开源的前端web框架推荐
B-JUI前端框架:http://demo.b-jui.com/ gentelella :https://colorlib.com/polygon/gentelella/ admui(收费):http ...
- Email feedback to product team about TFS and SharePoint Integration 2017.2.15
SharePoint与Team Foundation Server的集成,一直是许多研发团队所关注的问题. 通过这种集成,开发团队可以实现下面的几个功能: 1. 搭建一个与团队项目集成的门户网站,并 ...
- 项目笔记---事半功倍之StyleCop(一)
前言 曾几何时,你是否在看别人代码的时候总是在抱怨代码没有注释,命名不规范,代码风格不统一,代码可读性差?是否有一个适合团队开发规范的检查工具? 答案就是大名鼎鼎的StyleCop代码检查插件,有了这 ...
- jquery chosen 插件多选初始化
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...
- python 进程、线程、协程感悟
进程: 感觉只是使用Process模块加以使用即可: # -*- coding: utf-8 -*- # data:2019-02-23 21:23 # user:DIY # file:thread_ ...
- Django准备知识-web应用、http协议、web框架、Django简介
一.web应用 Web应用程序是一种可以通过web访问的应用程序(web应用本质是基于socket实现的应用程序),程序的最大好处是用户很容易访问应用程序,用户只需要有浏览器即可,不需要再安装其他软件 ...
- Dockerfile数据管理
本文介绍Docker内部以及容器间的数据管理,在容器中管理数据主要有两种方式: 数据卷(Volumes) 挂载主机目录(Bind mounts) 数据卷 数据卷是一个可供一个或则多个目录使用的特殊目录 ...