spring全局異常處理作用機制

最近遇到spring MVC中異常捕獲的問題,比較好奇spring是怎麼catch住exception然後調用exceptionHandler中的方法的。發現真相原來這麼簡單。。。。居然直接用的是try catch。

根據源碼可以看出,要實現異常攔截,可以實現一個類實現HandlerExceptionResolverOrdered 接口,後者主要用於排序,在spring容器中申明就可以了。

DispatcherServlet

大家都直到這是在Spring MVC中接收請求並分發請求的一個核心類。

主要注意異常處理器的加載和調用,分別在disaptcherServlet初始化和doDispatch中:

初始化

這個類在初始化時spring會首先調用onRefresh方法 。在這個方法中調用initStrategies() 方法。

protected void initStrategies(ApplicationContext context) {
        this.initMultipartResolver(context);
        this.initLocaleResolver(context);
        this.initThemeResolver(context);
        this.initHandlerMappings(context);
        this.initHandlerAdapters(context);
        this.initHandlerExceptionResolvers(context);
        this.initRequestToViewNameTranslator(context);
        this.initViewResolvers(context);
        this.initFlashMapManager(context);
    }

其中的this.initHandlerExceptionResolvers(context); 就是用於加載異常處理器的。

private void initHandlerExceptionResolvers(ApplicationContext context) {
        this.handlerExceptionResolvers = null;
        if (this.detectAllHandlerExceptionResolvers) {//默認爲true
            Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerExceptionResolvers = new ArrayList(matchingBeans.values());
 //根據resolver的order屬性排序
                AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
            }
        } else {
            try {
                HandlerExceptionResolver her = (HandlerExceptionResolver)context.getBean("handlerExceptionResolver", HandlerExceptionResolver.class);
                this.handlerExceptionResolvers = Collections.singletonList(her);
            } catch (NoSuchBeanDefinitionException var3) {
                ;
            }
        }

        if (this.handlerExceptionResolvers == null) {
            this.handlerExceptionResolvers = this.getDefaultStrategies(context, HandlerExceptionResolver.class);
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("No HandlerExceptionResolvers found in servlet '" + this.getServletName() + "': using default");
            }
        }

    }

可以看到,默認情況下會取spring容器中所有HandlerExceptionResolver 類型的bean,如果detectAllHandlerExceptionResolvers 爲false,則取name爲handlerExceptionResolver的bean。

會按照resolver的order屬性排序,放在List<HandlerExceptionResolver> handlerExceptionResolvers list裏。

doDispatch

  • 在覈心方法protected void doDispatch(HttpServletRequest request, HttpServletResponse response) 中首先依次調用各個攔截器的preHandle方法.
  • 然後調用真正controller的適配器HandlerAdapter對象的handle方法做真正的業務處理。
  • 最後再依次調用攔截器的postHandle方法。

  • 這些處理都包在try catch中。
    在catch了異常的時候會調用processHandlerException方法處理異常,這個方法依次調用DispatcherServlet屬性的handlerExceptionResolvers裏面的對象的resolveException 方法,如果一個resolver處理結果不爲空就返回。

  • 最後還會依次調用攔截器的afterCompletion方法
    這裏寫圖片描述

附上Dispatchservlet doDispatch 方法的代碼。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        int interceptorIndex = -1;

        try {
            boolean errorView = false;

            ModelAndView mv;
            try {
                label276: {
                    processedRequest = this.checkMultipart(request);
                    mappedHandler = this.getHandler(processedRequest, false);//根據url在handler的map中取得HandlerExecutionChain 對象,該對象中有一個處理業務的handler和攔截器的list
                    if (mappedHandler != null && mappedHandler.getHandler() != null) {
                        HandlerAdapter ha = this.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 (this.logger.isDebugEnabled()) {
                                String requestUri = urlPathHelper.getRequestUri(request);
                                this.logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
                            }

                            if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                                return;
                            }
                        }

                        HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
                        int i;
                        HandlerInterceptor interceptor;
                        if (interceptors != null) {
                            for(i = 0; i < interceptors.length; interceptorIndex = i++) {
                                interceptor = interceptors[i];
                                if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) { //執行攔截器的preHandle方法
                                    this.triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, (Exception)null);
                                    return;
                                }
                            }
                        }

                        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());//真執行controller的方法
                        if (mv != null && !mv.hasView()) {
                            mv.setViewName(this.getDefaultViewName(request));
                        }

                        if (interceptors == null) {
                            break label276;
                        }

                        i = interceptors.length - 1;

                        while(true) {
                            if (i < 0) {
                                break label276;
                            }

                            interceptor = interceptors[i];
                            interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv); //執行攔截器的postHandle方法
                            --i;
                        }
                    }

                    this.noHandlerFound(processedRequest, response);
                    return;
                }
            } catch (ModelAndViewDefiningException var20) {
                this.logger.debug("ModelAndViewDefiningException encountered", var20);
                mv = var20.getModelAndView();
            } catch (Exception var21) {
                Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;
                mv = this.processHandlerException(processedRequest, response, handler, var21);//異常處理,異常處理器註冊在Dispatcherservlet中

                errorView = mv != null;
            }

            if (mv != null && !mv.wasCleared()) {
                this.render(mv, processedRequest, response);//渲染view
                if (errorView) {
                    WebUtils.clearErrorRequestAttributes(request);
                }
            } else if (this.logger.isDebugEnabled()) {
                this.logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + this.getServletName() + "': assuming HandlerAdapter completed request handling");
            }

            this.triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, (Exception)null);
        } catch (Exception var22) {
            this.triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, var22);
            throw var22;
        } catch (Error var23) {
            ServletException ex = new NestedServletException("Handler processing failed", var23);
            this.triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
            throw ex;
        } finally {
            if (processedRequest != request) {
                this.cleanupMultipart(processedRequest);
            }

        }

    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章