spring源码解析-web系列(七):九大组件之HandlerExceptionResolver

spring源码解析-web系列(一):启动
spring源码解析-web系列(二):处理请求的过程
spring源码解析-web系列(三):九大组件之HandlerMapping
spring源码解析-web系列(四):九大组件之HandlerAdapter
spring源码解析-web系列(五):解析请求参数
spring源码解析-web系列(六):九大组件之ViewResolver
spring源码解析-web系列(七):九大组件之HandlerExceptionResolver

转载请标明出处:
https://blog.csdn.net/bingospunky/article/details/98947965
本文出自马彬彬的博客

HandlerExceptionResolver

HandlerExceptionResolver用来解析请求处理过程中产生的异常。

HandlerExceptionResolver的继承关系如下:

图1:

https://qingtian-blog.oss-cn-beijing.aliyuncs.com/spring%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90-web%E7%B3%BB%E5%88%97%28%E4%B8%83%29%3A%E4%B9%9D%E5%A4%A7%E7%BB%84%E4%BB%B6%E4%B9%8BHandlerExceptionResolver_1.png

1.AbstractHandlerExceptionResolver:是所有直接解析异常类的父类,定义了通用的解析流程。
2.AbstractHandlerMethodExceptionResolver:和其子类ExceptionHandlerExceptionResolver一起完成对@ExceptionHandler注解方法的处理。
3.DefaultHandlerExceptionResolver:根据异常的类型不同进行处理。
4.ResponseStatusExceptionResolver:解析@ResponseStatus注解类型的异常。
5.SimpleMappingExceptionResolver:通过配置异常类型和View的对应关系解析异常。

本文只介绍一下 AbstractHandlerMethodExceptionResolver 和它的子类,因为@ExceptionHandler是我们常用的异常处理方式,其他的方式很少使用。

AbstractHandlerExceptionResolver

代码1 (org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.resolveException):

	@Override
	public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
			Object handler, Exception ex) {

		if (shouldApplyTo(request, handler)) {
			// Log exception, both at debug log level and at warn level, if desired.
			if (this.logger.isDebugEnabled()) {
				this.logger.debug("Resolving exception from handler [" + handler + "]: " + ex);
			}
			logException(ex, request);
			prepareResponse(ex, response);
			return doResolveException(request, response, handler, ex);
		}
		else {
			return null;
		}
	}

代码1第5行判断是否可以解析这个handler抛出的异常,如果可以解析,则通过代码1第12行调用模板方法doResolveException让子类去解析该异常。判断是否可以解析handler的异常的逻辑也很简单:默认可以即系所有handler的异常;如果用户指定了某些handler对象或handler类型,则以用户指定的为准。

AbstractHandlerMethodExceptionResolver

AbstractHandlerMethodExceptionResolver是AbstractHandlerExceptionResolver的子类,主要工作就是对于handler是HandlerMethod时做一些适配。因为在父类的shouldApplyTo中,handler是对象,而对于HandlerMethod,handler是方法,该类通过handler获取它所在的Controller对象给父类的shouldApplyTo使用。该类剩下的一个工作就是抽象了一个 doResolveHandlerMethodException 供子类来解析异常使用。

ExceptionHandlerExceptionResolver

ExceptionHandlerExceptionResolver解析Exception的过程如下:

代码2 (org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver.doResolveHandlerMethodException):

	protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod, Exception exception) {
        ServletInvocableHandlerMethod exceptionHandlerMethod = this.getExceptionHandlerMethod(handlerMethod, exception);
        if (exceptionHandlerMethod == null) {
            return null;
        } else {
            exceptionHandlerMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
            exceptionHandlerMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
            ServletWebRequest webRequest = new ServletWebRequest(request, response);
            ModelAndViewContainer mavContainer = new ModelAndViewContainer();

            try {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Invoking @ExceptionHandler method: " + exceptionHandlerMethod);
                }

                exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, new Object[]{exception});
            } catch (Exception var9) {
                if (this.logger.isErrorEnabled()) {
                    this.logger.error("Failed to invoke @ExceptionHandler method: " + exceptionHandlerMethod, var9);
                }

                return null;
            }

            if (mavContainer.isRequestHandled()) {
                return new ModelAndView();
            } else {
                ModelAndView mav = (new ModelAndView()).addAllObjects(mavContainer.getModel());
                mav.setViewName(mavContainer.getViewName());
                if (!mavContainer.isViewReference()) {
                    mav.setView((View)mavContainer.getView());
                }

                return mav;
            }
        }
    }

代码2第2行通过handlerMethod和exception获取到ServletInvocableHandlerMethod对象,ServletInvocableHandlerMethod对象就是我们 @ExceptionHandler 注解标记的方法。后面的过程和 RequestMappingHandlerAdapter 里的处理流程相似,就像是一个简化版的 RequestMappingHandlerAdapter ,因为他们都是controller里的处理逻辑,区别只是一个处理异常,一个处理用户的请求而已,这里就不展开介绍了,可以参考博客 spring源码解析-web系列(四):九大组件之HandlerAdapter

代码2第2行通过handlerMethod和exception获取到ServletInvocableHandlerMethod对象的过程如下:

代码3 (org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver.getExceptionHandlerMethod):

	protected ServletInvocableHandlerMethod getExceptionHandlerMethod(HandlerMethod handlerMethod, Exception exception) {
        Class<?> handlerType = handlerMethod != null ? handlerMethod.getBeanType() : null;
        if (handlerMethod != null) {
            ExceptionHandlerMethodResolver resolver = (ExceptionHandlerMethodResolver)this.exceptionHandlerCache.get(handlerType);
            if (resolver == null) {
                resolver = new ExceptionHandlerMethodResolver(handlerType);
                this.exceptionHandlerCache.put(handlerType, resolver);
            }

            Method method = resolver.resolveMethod(exception);
            if (method != null) {
                return new ServletInvocableHandlerMethod(handlerMethod.getBean(), method);
            }
        }

        Iterator var8 = this.exceptionHandlerAdviceCache.entrySet().iterator();

        while(var8.hasNext()) {
            Entry<ControllerAdviceBean, ExceptionHandlerMethodResolver> entry = (Entry)var8.next();
            if (((ControllerAdviceBean)entry.getKey()).isApplicableToBeanType(handlerType)) {
                ExceptionHandlerMethodResolver resolver = (ExceptionHandlerMethodResolver)entry.getValue();
                Method method = resolver.resolveMethod(exception);
                if (method != null) {
                    return new ServletInvocableHandlerMethod(((ControllerAdviceBean)entry.getKey()).resolveBean(), method);
                }
            }
        }

        return null;
    }

代码3第2第14行获取当前handlerMethod所在的类里注解了@ExceptionHandler的匹配的方法。代码2第16第27行获取被@ControllerAdvice注解的类里注解了@ExceptionHandler的匹配的方法。

在获取注解了@ExceptionHandler的匹配的方法时,使用的是 ExceptionHandlerMethodResolver 这个类。正如代码3第10行,ExceptionHandlerMethodResolver的resolveMethod方法的处理过程:首先获取类里所有注解了@ExceptionHandler的方法,然后根据@ExceptionHandler方法能处理的异常类型和当前实际的异常类型进行匹配。

总结

HandlerExceptionResolver的作用就是解析异常,具体工作就是:将异常相关信息设置到Model、给response设置响应属性。

mvc:annotation-driven 会将ExceptionHandlerExceptionResolver、DefaultHandlerExceptionResolver、ResponseStatusExceptionResolver设置到DispatcherServlet的handlerExceptionResolvers属性中。

HandlerExceptionResolver只处理请求处理过程中的异常,异常处理本身抛出的异常和渲染视图的异常不归它处理。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值