【源码阅读】HandlerExceptionResolver的部分源码阅读

起因

Spring Rest调用的异常处理 的相关源码学习

源码阅读

  1. 由于 @ExceptionHandler 只能做用在 @Controller 上,所以 @ExceptionHandler 的处理逻辑应该和 @Controller 处理的时机一样,所以关注点应该在 DispatcherServlet 核心类的 doDispatch() 方法

  2. DispatcherServlet 的 doDispatch() 方法

    	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
            HttpServletRequest processedRequest = request;
            HandlerExecutionChain mappedHandler = null;
            boolean multipartRequestParsed = false;
    
            WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    
            try {
                ModelAndView mv = null;
                Exception dispatchException = null;
    
                try {
                    processedRequest = checkMultipart(request);
                    multipartRequestParsed = (processedRequest != request);
    
                    mappedHandler = getHandler(processedRequest);
                    if (mappedHandler == null) {
                        noHandlerFound(processedRequest, response);
                        return;
                    }
    
                    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
                    String method = request.getMethod();
                    boolean isGet = "GET".equals(method);
                    if (isGet || "HEAD".equals(method)) {
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                        if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }
    
                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }
    
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }
    
                    applyDefaultViewName(processedRequest, mv);
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                }
                catch (Exception ex) {
                    dispatchException = ex;
                }
                catch (Throwable err) {
                    dispatchException = new NestedServletException("Handler dispatch failed", err);
                }
                // dispatchException就是捕捉到的所有异常,所以这里是处理异常的逻辑
                processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
            }
            catch (Exception ex) {
                triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
            }
            catch (Throwable err) {
                triggerAfterCompletion(processedRequest, response, mappedHandler,
                        new NestedServletException("Handler processing failed", err));
            }
            finally {
                if (asyncManager.isConcurrentHandlingStarted()) {
                    if (mappedHandler != null) {
                        mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                    }
                }
                else {
                    if (multipartRequestParsed) {
                        cleanupMultipart(processedRequest);
                    }
                }
            }
        }
    
  3. DispatcherServlet 的 processDispatchResult() 方法

    	private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable  ModelAndView mv, @Nullable Exception exception) throws Exception {
    
            boolean errorView = false;
    
            // 判断是不是有异常
            if (exception != null) {
                // 处理 ModelAndViewDefiningException 类型异常
                if (exception instanceof ModelAndViewDefiningException) {
                    logger.debug("ModelAndViewDefiningException encountered", exception);
                    mv = ((ModelAndViewDefiningException) exception).getModelAndView();
                }
                else {
                // 处理其他类型的异常    
                    Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
                    mv = processHandlerException(request, response, handler, exception);
                    errorView = (mv != null);
                }
            }
    
            if (mv != null && !mv.wasCleared()) {
                render(mv, request, response);
                if (errorView) {
                    WebUtils.clearErrorRequestAttributes(request);
                }
            }
            else {
                if (logger.isTraceEnabled()) {
                    logger.trace("No view rendering, null ModelAndView returned.");
                }
            }
    
            if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
                return;
            }
    
            if (mappedHandler != null) {
                mappedHandler.triggerAfterCompletion(request, response, null);
            }
        }
    
  4. DispatcherServlet 的 processDispatchResult() 方法

    	@Nullable
        protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) throws Exception {
    
            request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
    
            ModelAndView exMv = null;
            if (this.handlerExceptionResolvers != null) {
                // 这里看出,处理异常的Resolver是本类的一个属性里边遍历出来 那就搜一下这个属性在哪里set的值 
                for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
                    // 这里调用的就是ExceptionHandlerExceptionResolver的resolveException()方法
                    // 这里把异常转化成了 ModelAndView
                    exMv = resolver.resolveException(request, response, handler, ex);
                    if (exMv != null) {
                        break;
                    }
                }
            }
            if (exMv != null) {
                if (exMv.isEmpty()) {
                    request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
                    return null;
                }
                if (!exMv.hasView()) {
                    String defaultViewName = getDefaultViewName(request);
                    if (defaultViewName != null) {
                        exMv.setViewName(defaultViewName);
                    }
                }
                if (logger.isTraceEnabled()) {
                    logger.trace("Using resolved error view: " + exMv, ex);
                }
                else if (logger.isDebugEnabled()) {
                    logger.debug("Using resolved error view: " + exMv);
                }
                WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
                return exMv;
            }
    
            throw ex;
        }
    
  5. DispatcherServlet 的 initHandlerExceptionResolvers() 方法

        private void initHandlerExceptionResolvers(ApplicationContext context) {
            this.handlerExceptionResolvers = null;
    
            if (this.detectAllHandlerExceptionResolvers) {
                // Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts.
                // 这里官方注解也说了,从ApplicationContext中找到所有HandlerExceptionResolvers,HandlerExceptionResolvers作为接口,它的实现类就有ExceptionHandlerExceptionResolver,所以这里也是遍历出了所有的ExceptionHandlerExceptionResolver
                Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false;
                if (!matchingBeans.isEmpty()) {
                    this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values());
                    AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
                }
            }
            else {
                try {
                    HandlerExceptionResolver her = context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);
                    this.handlerExceptionResolvers = Collections.singletonList(her);
                }
                catch (NoSuchBeanDefinitionException ex) {
                }
            }
    
            if (this.handlerExceptionResolvers == null) {
                this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);
                if (logger.isTraceEnabled()) {
                    logger.trace("No HandlerExceptionResolvers declared in servlet '" + getServletName() + "': using default strategies from DispatcherServlet.properties");
                }
            }        
        }
    
  6. AbstractHandlerExceptionResolver 的 resolveException() 方法。这里是使用了模板模式。父类接口 HandlerExceptionResolvers 定义了空的 resolveException() 方法。ExceptionHandlerExceptionResolver 继承了 AbstractHandlerMethodExceptionResolver,AbstractHandlerMethodExceptionResolver 又继承了 AbstractHandlerExceptionResolver。而AbstractHandlerExceptionResolver。而实现了 HandlerExceptionResolvers。真正的模板方法在 AbstractHandlerExceptionResolver 中。ExceptionHandlerExceptionResolver 通过继承的方法直接使用了父类的方法

    	@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;
            }
        }
    
        // 这里还是个模板模式  AbstractHandlerExceptionResolver定义了处理异常的抽象方法doResolveException
        @Nullable
        protected abstract ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);
    
  7. AbstractHandlerMethodExceptionResolver 的 doResolveException() 方法

    	@Override
        @Nullable
        protected final ModelAndView doResolveException(
                HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
    
            return doResolveHandlerMethodException(request, response, (HandlerMethod) handler, ex);
        }
    
    
        // 模板模式
        @Nullable
        protected abstract ModelAndView doResolveHandlerMethodException(
                HttpServletRequest request, HttpServletResponse response, @Nullable HandlerMethod handlerMethod, Exception ex);
    
    
  8. ExceptionHandlerExceptionResolver 的 doResolveHandlerMethodException()

    	@Override
        @Nullable
        protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerMethod handlerMethod, Exception exception) {
    
            ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);
            if (exceptionHandlerMethod == null) {
                return null;
            }
    
            if (this.argumentResolvers != null) {
                exceptionHandlerMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
            }
            if (this.returnValueHandlers != null) {
                exceptionHandlerMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
            }
    
            ServletWebRequest webRequest = new ServletWebRequest(request, response);
            ModelAndViewContainer mavContainer = new ModelAndViewContainer();
    
            try {
                if (logger.isDebugEnabled()) {
                    logger.debug("Using @ExceptionHandler " + exceptionHandlerMethod);
                }
                Throwable cause = exception.getCause();
                if (cause != null) {
                    // Expose cause as provided argument as well
                    // 获取参数和原因
                    exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception, cause, handlerMethod);
                }
                else {
                    // Otherwise, just the given exception as-is
                    // 获取参数
                    exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception, handlerMethod);
                }
            }
            catch (Throwable invocationEx) {
                // Any other than the original exception (or its cause) is unintended here,
                // probably an accident (e.g. failed assertion or the like).
                if (invocationEx != exception && invocationEx != exception.getCause() && logger.isWarnEnabled()) {
                    logger.warn("Failure in @ExceptionHandler " + exceptionHandlerMethod, invocationEx);
                }
                // Continue with default processing of the original exception...
                return null;
            }
    
            if (mavContainer.isRequestHandled()) {
                return new ModelAndView();
            }
            else {
                ModelMap model = mavContainer.getModel();
                HttpStatus status = mavContainer.getStatus();
                ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, status);
                mav.setViewName(mavContainer.getViewName());
                if (!mavContainer.isViewReference()) {
                    mav.setView((View) mavContainer.getView());
                }
                if (model instanceof RedirectAttributes) {
                    Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
                    RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
                }
                return mav;
            }
        }
    
  9. ServletInvocableHandlerMethod 的 invokeAndHandle()

        public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
                Object... providedArgs) throws Exception {
    
            Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
            setResponseStatus(webRequest);
    
            if (returnValue == null) {
                if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
                    disableContentCachingIfNecessary(webRequest);
                    mavContainer.setRequestHandled(true);
                    return;
                }
            }
            else if (StringUtils.hasText(getResponseStatusReason())) {
                mavContainer.setRequestHandled(true);
                return;
            }
    
            mavContainer.setRequestHandled(false);
            Assert.state(this.returnValueHandlers != null, "No return value handlers");
            try {
                this.returnValueHandlers.handleReturnValue(
                        returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
            }
            catch (Exception ex) {
                if (logger.isTraceEnabled()) {
                    logger.trace(formatErrorForReturnValue(returnValue), ex);
                }
                throw ex;
            }
        }
    
  10. InvocableHandlerMethod 的 invokeForRequest()

        @Nullable
        public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
            // 获取配置的参数
            Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Arguments: " + Arrays.toString(args));
            }
    
            // 执行
            return this.doInvoke(args);
        }
    
  11. 再往下就是获取可以配置的参数了,其实 ExceptionHandlerExceptionResolver 实现了 InitializingBean。重写了 afterPropertiesSet() 方法,所以每次调用的时候都可以刷新参数

    	@Override
        public void afterPropertiesSet() {
            // Do this first, it may add ResponseBodyAdvice beans
            initExceptionHandlerAdviceCache();
    
            if (this.argumentResolvers == null) {
                List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
                this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
            }
            if (this.returnValueHandlers == null) {
                List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
                this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
            }
        }
    
        private void initExceptionHandlerAdviceCache() {
            if (getApplicationContext() == null) {
                return;
            }
    
            // 扫描 @ControllerAdvice 注解
            List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
            for (ControllerAdviceBean adviceBean : adviceBeans) {
                Class<?> beanType = adviceBean.getBeanType();
                if (beanType == null) {
                    throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);
                }
                // 查询所有 @ExceptionHandler 注解
                ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(beanType);
                if (resolver.hasExceptionMappings()) {
                    this.exceptionHandlerAdviceCache.put(adviceBean, resolver);
                }
                if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
                    this.responseBodyAdvice.add(adviceBean);
                }
            }
    
            if (logger.isDebugEnabled()) {
                int handlerSize = this.exceptionHandlerAdviceCache.size();
                int adviceSize = this.responseBodyAdvice.size();
                if (handlerSize == 0 && adviceSize == 0) {
                    logger.debug("ControllerAdvice beans: none");
                }
                else {
                    logger.debug("ControllerAdvice beans: " +
                            handlerSize + " @ExceptionHandler, " + adviceSize + " ResponseBodyAdvice");
                }
            }
        }
    
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值