SpringMVC 异常处理体系深入分析

SpringMVC 中针对异常问题有一套完整的处理体系,这套体系非常好用,今天松哥就花点时间来和大家聊一聊 SpringMVC 中的异常处理体系,我们把 SpringMVC 中的异常体系从头到尾梳理一下。

1.异常解析器概览

在 SpringMVC 的异常体系中,处于最顶层的大 Boss 是 HandlerExceptionResolver,这是一个接口,里边只有一个方法:

public interface HandlerExceptionResolver {
 @Nullable
 ModelAndView resolveException(
   HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);
}

resolveException 方法就用来解析请求处理过程中所产生的异常,并最终返回一个 ModelAndView。

我们来看下 HandlerExceptionResolver 的实现类:

直接实现 HandlerExceptionResolver 接口的类有三个:

  • HandlerExceptionResolverComposite:这个一看又是一个组合,在最近的源码分析中我们已经多次见到 xxxComposite 了,这里就不再赘述。

  • DefaultErrorAttributes:这个用来保存异常属性。

  • AbstractHandlerExceptionResolver:这个的子类比较多:

    • SimpleMappingExceptionResolver:通过提前配置好的异常类和 View 之间的对应关系来解析异常。

    • AbstractHandlerMethodExceptionResolver:处理使用 @ExceptionHandler 注解自定义的异常类型。

    • DefaultHandlerExceptionResolver:按照不同类型来处理异常。

    • ResponseStatusExceptionResolver:处理含有 @ResponseStatus 注解的异常。

在 SpringMVC 中,大致的异常解析器就是这些,接下来我们来逐个学习这些异常解析器。

2.AbstractHandlerExceptionResolver

AbstractHandlerExceptionResolver 是真正干活的异常解析器的父类,我们就先从他的 resolveException 方法开始看起。

@Override
@Nullable
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
 if (shouldApplyTo(request, handler)) {
  prepareResponse(ex, response);
  ModelAndView result = doResolveException(request, response, handler, ex);
  if (result != null) {
   logException(ex, request);
  }
  return result;
 }
 else {
  return null;
 }
}
  1. 首先调用 shouldApplyTo 方法判断当前解析器是否可以处理传入的处理器所抛出的异常,如果不支持,则直接返回 null,这个异常将交给下一个 HandlerExceptionResolver 去处理。

  2. 调用 prepareResponse 方法处理 response。

  3. 调用 doResolveException 方法实际处理异常,这是一个模版方法,具体的实现在子类中。

  4. 调用 logException 方法记录异常日志信息。

记录异常日志没啥好说的,doResolveException 则是一个空的模版方法,所以这里对我们来说主要就是两个方法:shouldApplyTo 和 prepareResponse,我们分别来看。

shouldApplyTo

protected boolean shouldApplyTo(HttpServletRequest request, @Nullable Object handler) {
 if (handler != null) {
  if (this.mappedHandlers != null && this.mappedHandlers.contains(handler)) {
   return true;
  }
  if (this.mappedHandlerClasses != null) {
   for (Class<?> handlerClass : this.mappedHandlerClasses) {
    if (handlerClass.isInstance(handler)) {
     return true;
    }
   }
  }
 }
 return !hasHandlerMappings();
}

这里涉及到了两个对象:mappedHandlers 和 mappedHandlerClasses:

  • mappedHandlers:存储的是处理器对象(Controller 或者 Controller 中的方法)

  • mappedHandlerClasses:存储的是处理器的 Class。

我们在配置异常解析器的时候可以配置这两个对象,进而实现该异常处理器只为某一个处理器服务,但是一般来说没这种需求,所以大家仅做了解即可。

如果开发者一开始配置了 mappedHandlers 或者 mappedHandlerClasses,则用这两个和处理器去比较,否则就直接返回 true,表示支持该异常处理。

prepareResponse

prepareResponse 方法比较简单,主要是处理一下响应头的缓存字段。

protected void prepareResponse(Exception ex, HttpServletResponse response) {
 if (this.preventResponseCaching) {
  preventCaching(response);
 }
}
protected void preventCaching(HttpServletResponse response) {
 response.addHeader(HEADER_CACHE_CONTROL, "no-store");
}

这是 AbstractHandlerExceptionResolver 的大致内容,可以看到还是非常 easy 的,接下来我们来看它的实现类。

2.1 AbstractHandlerMethodExceptionResolver

AbstractHandlerMethodExceptionResolver 主要是重写了 shouldApplyTo 方法和 doResolveExceptio

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值