在上一篇文章Spring与MVC(五)中,我们分析了Spring MVC是如何处理方法参数以及响应返回值。在这篇文章中,我们来分析一下Spring MVC如何处理异常。
- 程序在
DispatcherServlet.doDispatch方法中调用ha.handle执行相应的函数,这时抛出异常,异常赋值给dispatchException。 - 调用
processDispatchResult方法处理捕获的异常。
processHandlerException
在DispatcherServlet.processDispatchResult方法的processHandlerException中调用HandlerExceptionResolverComposite.resolveException,遍历所有的异常处理器(实现HandlerExceptionResolver接口),处理异常
1 | public ModelAndView resolveException(HttpServletRequest request, |
其中默认的异常处理器有3个:
- ExceptionHandlerExceptionResolver
- ResponseStatusExceptionResolver
- DefaultHandlerExceptionResolver
如果经过这三个异常处理器处理之后得到的ModelAndView为null,则继续抛出异常,最后由servlet容器来处理
DefaultHandlerExceptionResolver
继承自AbstractHandlerExceptionResolver,主要对一些特殊的异常进行处理,比如NoSuchRequestHandlingMethodException, HttpRequestMethodNotSupportedException, HttpMediaTypeNotSupportedException, HttpMediaTypeNotAcceptableException等
ResponseStatusExceptionResolver
继承自AbstractHandlerExceptionResolver,主要在异常父类中找到@ResponseStatus注解,然后使用这个注解的属性进行处理
ExceptionHandlerExceptionResolver
继承自AbstractHandlerMethodExceptionResolver,该类主要处理Controller中用@ExceptionHandler注解定义的方法,大多数异常处理都是由该类操作。
我们来看看ExceptionHandlerExceptionResolver在用户controller方法调用抛出异常时是如何工作的:
在DispatcherServlet.doDispatch方法中执行ha.handle调用用户的controller方法,抛出异常后被catch捕获,将异常赋值给dispatchException变量。
然后调用processDispatchResult方法来处理执行结果或者抛出的异常。当然这里关注的是处理抛出的异常:
1 | if (exception != null) { |
我们看到,如果我们的异常不是ModelAndViewDefinitionException,则调用processHandlerException:遍历handlerExceptionResolvers,其中其中的resolveException遍历所有的HandlerExceptionResolver处理异常。
来看ExceptionHandlerExceptionResolver

它的resolveException方法在父类AbstractHandlerExceptionResolver中。它的主要工作是调用doResolveException处理异常并返回ModelAndView。doResolveException调用doResolveHandlerMethodException,doResolveHandlerMethodException在ExceptionHandlerExceptionResolver中实现:
首先调用
getExceptionHandlerMethod获取异常处理的方法exceptionHandlerMethod- 先获取controller方法的类型
根据controller方法的类型获取处理异常的方法,具体的过程在
ExceptionHandlerMethodResolver类的构造函数中1
2
3
4
5
6
7public ExceptionHandlerMethodResolver(Class<?> handlerType) {
for (Method method : MethodIntrospector.selectMethods(handlerType, EXCEPTION_HANDLER_METHODS)) {
for (Class<? extends Throwable> exceptionType : detectExceptionMappings(method)) {
addExceptionMapping(exceptionType, method);
}
}
}在
MethodIntrospector.selectMethods方法中获取所有controller方法对应的异常处理方法,调用detectExceptionMappings获取异常处理函数的处理的异常类型,然后将异常类型与异常处理方法的键值对添加到ExceptionHandlerMethodResolver的mappedMethods中。调用
ExceptionHandlerMethodResolver.resolveMethod方法根据异常获取异常处理方法
调用
exceptionHandlerMethod的invokeAndHandle方法执行异常处理方法执行异常处理方法的过程与执行普通的controller方法一致
回到DispatcherServlet的processDispatchResult方法,如果调用processHandlerException方法返回的ModelAndView不为null则渲染页面。