文章目录

  • 2020.12.29修改
  • 问题:拦截器里面抛出异常,全局异常处理能捕获吗?
  • 测试
  • 结论
  • 源码分析
  • 2022-03-14
  • 先说这篇文章的讨论点,拦截器里面抛出异常走不走异常解析器
  • 请求走/error


2020.12.29修改

发现这篇文章很多新手哥们看,当时我也是刚写博客,格式比较差,而且也没有将代码贴出来,很多人都说以偏概全~我想的是,这个这么简单的代码,自己随便找个代码试一下不就好了,想了想,还是重新编辑一下好了:

问题:拦截器里面抛出异常,全局异常处理能捕获吗?

很多朋友私信问我拦截器里面抛出异常,全局异常处理能捕获吗?
然后我认问是可以的,但是需要用代码说话:
先随便写个拦截器:拦截器的几个方法就不多说了我demo试的是preHandle方法,在一开始请求就会进来:

@Slf4j
public class LoginInterceptor implements HandlerInterceptor {

  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    String requestURI = request.getRequestURI();
    log.info("request uri : {}", requestURI);
    throw new RuntimeException("aaa");
//    return true;
  }

}

然后我的全局异常处理是这样的异常处理简单了解:

@ControllerAdvice
public class GlobalHandlerExceptionResolver {

  private final Logger log = LoggerFactory.getLogger(getClass());

  @ExceptionHandler(Exception.class)
  @ResponseBody
  public ResponseResult allExceptionHandler(Exception e) {
    log.info("================进入异常处理================");
    ResponseResult result = new ResponseResult(e.getMessage(), 500);
    throw new NullPointerException("bbb");
//        return result;
  }

}

测试

请求/ 的时候发现跳转到/error 页面报错;请求不存在的url的时候就会跳转到/error然后报错;

请求/aaa(/aaa在controller里面配置了,存在RequestMapping为"/aaa")的时候发现抛异常就直接进入到异常解析器;

结论

在controller里面配置了,存在RequestMapping为"/aaa")的时候发现抛异常就直接进入到异常解析器;
否则就不会进入异常解析器;

源码分析

最近在看spring源码,看完再来分析

2022-03-14

发现好多兄弟还在看这篇文章,现在有一点springmvc的源码基础,对原先的问题进行一个简单回顾.项目中有存在RequestMapping为"/aaa"),没有对应的/ccc的处理方法.

  • 请求/ccc没有对应的处理器的时候,会直接请求到/error,没有执行到异常解析器.
  • 请求到/error的时候,拦截器抛出异常,进入异常解析器.
  • 请求/aaa的时候,拦截器抛出异常,进入异常解析器.

我先总结一下,
当有对应的处理器的时候,拦截器里面抛出异常会走到异常解析器.
当没有对应处理器的时候,拦截器里面抛出异常不会走到异常解析器.

我测试使用的是springboot项目,当找不到的对应的controller地址映射,handler映射也不到就走/error结束。
springboot项目有个默认的/error解析器,BasicErrorController,这时候/error相当于有了处理器.就会执行到异常解析器.
请求/aaa的时候同/error,在拦截器里面抛出异常会走到异常解析器.

先说这篇文章的讨论点,拦截器里面抛出异常走不走异常解析器

在DispatcherServlet的方法doDispatch里面,有个异常处理的方法,processDispatchResult;

异常处理能捕获拦截器intercepter里面抛出的异常吗?_解析器


异常处理能捕获拦截器intercepter里面抛出的异常吗?_spring_02

异常处理能捕获拦截器intercepter里面抛出的异常吗?_spring boot_03

接下来就执行到了AbstractHandlerExceptionResolver解析器,我们写的异常解析器都会被转成这个的子类

@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) {
				// Print debug message when warn logger is not enabled.
				if (logger.isDebugEnabled() && (this.warnLogger == null || !this.warnLogger.isWarnEnabled())) {
					logger.debug("Resolved [" + ex + "]" + (result.isEmpty() ? "" : " to " + result));
				}
				// Explicitly configured warn logger in logException method.
				logException(ex, request);
			}
			return result;
		}
		else {
			return null;
		}
	}

shouldApplyTo方法就会去判断执不执行对应的异常处理器,AbstractHandlerExceptionResolver的shouldApplyTo方法就是判断对应的handler处理器是不是HandlerMethod,如果是的话就会会执行对应的异常处理器,如果不是就返回false就不会执行对应的异常处理器了.而/ccc请求没有对应的handler处理器,所以返回false了…

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;
					}
				}
			}
		}
		// Else only apply if there are no explicit handler mappings.
		return (this.mappedHandlers == null && this.mappedHandlerClasses == null);
	}

请求走/error

springmvc没有对应的处理器的时候,会直接请求到/error,