背景

开发过程中,会出现很多异常情况,比如RPC调用异常、请求参数异常,SpringMVC是如何处理异常信息的?

Spring处理异常的方式

Spring采用了全局的异常捕获统一处理的方式,虽然JAVA的异常机制一直有争议,但是Spring还是选择基于实际开发需要使用抛异常后捕获统一处理的方式

HandlerExceptionResolver登场

HandlerExceptionResolver 是SpringMVC提供的解析Handler调用过程抛出异常的解析器,只提供了一个解析异常的方法 resovleException

Spring提供了哪些ExceptionResolver?

经典的Interface-Abstract方式的实现类

Resolver Desc
SimpleMappingExceptionResolver 提供exception class name到view的映射
DefaultHandlerExceptionResolver 默认Resolver实现,用于解析标准的SpringMVC异常并转换成对应的Http状态码
ResponseStatusExceptionResolver 基于 @ResponseStatus 注解来映射异常与Http状态码
ExceptionHandlerExceptionResolver 基于 @ExceptionHalder 注解来解析处理异常信息

直接实现HandlerExceptionResolver的类

Resolver Desc
DefaultErrorAttributes 默认错误属性实现
HandlerExceptionResolverComposite 代理其它Resolver集合的ExceptionResolver

HandlerExceptionResolverComposite 中包含了一个解析列表,可以判断是会排序后顺序调用,以找到第一个可以处理的Resolver

具体异常处理流程

异常处理的核心逻辑都在 processHandlerException 方法中,Spring处理完请求后,如果有异常抛出,则会把异常信息传给 processHandlerException 方法, processHandlerException 遍历持有的 handlerExceptionResolvers 进行对异常的解析,如果解析成功则直接返回对应的 ModelAndView(此返回与正常的handler处理返回保持了一致)

handlerExceptionResolvers 有哪些?

在 SpringMVC启动时会调用 initHandlerExceptionResolvers 方法来查找所有可用的 handlerExceptionResolver 并保存到 handlerExceptionResolvers 变量中。SpringMVC配置了两个 resolver 来提供异常解析

errorAttributes

此Resolver是在 ErrorMvcAutoConfiguration 进行实例化的

此实现的 resolverExcption 方法逻辑简单,直接返回了null,不是关注重点

handlerExceptionResolver

此Resolver真正的实现类为 HandlerExceptionResolverComposite ,也就是持有多个ExceptionResolver列表的 Resolver,它是在 WebMvcConfigurationSupport 实例化的

在此方法中设置了 HandlerExceptionResolverComposite , 那 HandlerExceptionResolverComposite 持有哪些 ExceptionResolver?

由图可知, HandlerExceptionResolverComposite 持有 ExceptionHandlerExceptionResolver 、ResponseStatusExceptionResolver 、DefaultHandlerExceptionResolver 3个Resolver,这些Resolver才是真正干活的Resolver

细说说ExceptionHandler

Spring 3.0 开始支持通过配置 @ControllerAdvice@ExceptionHandler 注解的方式来处理全局异常,通过配置的不同的注解参数类型与支持的方法参数类型进行细粒度的异常匹配,配置样例

实现逻辑

处理 @ExceptionHandler 注解对应的实现类为 ExceptionHandlerExceptionResolver

从上图可知 @ExceptionHanlder 是通过持有 HandlerMethodArgumentResolverCompositeHandlerMethodReturnValueHandlerComposite 支持不同参数类型与返回值的

注解配置在何时生效

对应配置的 ExceptionHandler 是在创建 ExceptionHandlerExceptionResolver 进行处理的,核心代码逻辑在 WebMvcConfigurationSupport#addDefaultHandlerExceptionResolvers , 它调用了 exceptionHandlerResolver.afterPropertiesSet() ,在此方法时会扫描配置的 @ExceptionHandler 并将参数与返回值进行保存

有异常时如何匹配对应的 ExceptionHandler

当有异常抛出时,最终会调用 ExceptionHandlerExceptionResolver 的 doResolveHandlerMethodException 方法匹配对应 exceptionHandlerMethod ,然后执行注解标识方法的逻辑,这样就实现了对不同异常的自定义逻辑处理。

ExceptionHandler匹配顺序为:当前Controller -> 全局配置的ExceptionHandler

如何解析对应的异常

核心逻辑在 ExceptionHandlerMethodResolverresolveMethodByThrowable 方法,先根据原始异常查,查不到,遍历查询异常的 Cause 异常