SpringMVC doDispatch方法的基本思路梳理

SpringMVC doDispatch方法的基本思路梳理

在分析之前,先介紹一個類

1、HandlerExecutionChain

    public class HandlerExecutionChain {
        private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
        private final Object handler;
        private HandlerInterceptor[] interceptors;
        private List<HandlerInterceptor> interceptorList;
        private int interceptorIndex;

該類中主要包括了一個用於處理request的handler,以及和request相關的一系列攔截器interceptors.

進入正題,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 {
            try {
                ModelAndView mv = null;
                Exception dispatchException = null;

                try {
                    processedRequest = this.checkMultipart(request);
                    multipartRequestParsed = processedRequest != request;
                    /*
                    分析1,其目的是:得到包含了用於處理request的HandlerMethod、Interceptors。
                    */
                    mappedHandler = this.getHandler(processedRequest, false);
                    //如果沒有,則說明沒有處理器能夠處理該request,因此返回404錯誤。
                    if(mappedHandler == null || mappedHandler.getHandler() == null) {
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }
                        /*
                        分析2,其目的是:得到與Handler匹配的HandlerAdapter。
                        */
                    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()) {
                            this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                        }

                        if((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }
                        /*
                        分析3:執行所有註冊攔截器的preHandler方法
                        */
                    if(!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }

                    try {
                    //前面的第一步就是找到用於處理request的handler,到這裏才真正意思上的執行用於處理request的handler方法。具體後面進行分析
                        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    } finally {
                        if(asyncManager.isConcurrentHandlingStarted()) {
                            return;
                        }

                    }

                    this.applyDefaultViewName(request, mv);
                    /*
                    分析4:執行所有註冊攔截器的postHandler方法
                    */
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var27) {
                    dispatchException = var27;
                }

                this.processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
            } catch (Exception var28) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, var28);
            } catch (Error var29) {
                this.triggerAfterCompletionWithError(processedRequest, response, mappedHandler, var29);
            }

        } finally {
            if(asyncManager.isConcurrentHandlingStarted()) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                return;
            } else {
                if(multipartRequestParsed) {
                    this.cleanupMultipart(processedRequest);
                }

            }
        }
    }

doDispatch方法主要邏輯如下:

1)找到用於處理request的handler和interceptors,構造成一個HandlerExecutionChain.

2) 找到與用於處理request的handler相匹配的HandlerAdapter,目的是:後續將使用此HandlerAdapter來執行handler。

3)執行所有註冊攔截器的preHandler方法

4)真正意思上的執行用於request的handler方法,得到ModelAndView

5)倒序執行所有註冊攔截器的postHandler方法。

6)解析並返回ModelAndView

主要是理清思路,本篇博文將依次分析除第4點之外的幾點。

分析1:找到用於處理request的handler和interceptors,構造成一個HandlerExecutionChain.

    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        for (HandlerMapping hm : this.handlerMappings) {
            if (logger.isTraceEnabled()) {
                logger.trace(
                        "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
            }
            HandlerExecutionChain handler = hm.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
        return null;
    }

該函數的功能爲:遍歷DispatcherServlet中的private List handlerMappings; 看哪個HandlerMapping能夠處理該request,則返回由

AbstractHandlerMapping.java

    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        Object handler = getHandlerInternal(request);//第一步
        if (handler == null) {
            handler = getDefaultHandler();
        }
        if (handler == null) {
            return null;
        }
        // Bean name or resolved handler?
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = getApplicationContext().getBean(handlerName);
        }
        //第二步
        return getHandlerExecutionChain(handler, request);
    }

此方法的主要邏輯如下:

第一步:根據request中的url得到相應的handler,此handler爲HandlerMethod的實例。

第二步:將第一步得到的HandlerMethod作爲參數實例化一個HandlerExecutionChain對象。在實例化過程中,還需要得到與request相關的Interceptors。

下面將逐一的分析這兩步所涉及到具體實現。

先看第一步:根據request中的url得到相應的handler,此handler爲HandlerMethod的實例

getHandlerInternal方法的代碼如下:

    AbstractHandlerMethodMapping.java   

    @Override
    protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
        if (logger.isDebugEnabled()) {
            logger.debug("Looking up handler method for path " + lookupPath);
        }
        //得到與request相關的handlerMethod,如何得到的,就是在Map中來尋找
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        if (logger.isDebugEnabled()) {
            if (handlerMethod != null) {
                logger.debug("Returning handler method [" + handlerMethod + "]");
            }
            else {
                logger.debug("Did not find handler method for [" + lookupPath + "]");
            }
        }
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }   

getHandlerInternal函數的功能:就是在Map中尋找HandlerMethod方法。Map中保存的是<url,HandlerMethod>,Map中的內容如何來的呢:是在容器初始化時會建立所有url和controller的對應關係,保存到Map

    protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
        HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
                (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
        chain.addInterceptors(getAdaptedInterceptors());

        String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
        for (MappedInterceptor mappedInterceptor : this.mappedInterceptors) {
            if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                chain.addInterceptor(mappedInterceptor.getInterceptor());
            }
        }

        return chain;
    }

其中,private final List<MappedInterceptor> mappedInterceptors =
new ArrayList<MappedInterceptor>();
中保存的是我們項目配置文件配置的攔截器。

分析2:找到與用於處理request的handler相匹配的HandlerAdapter

DispatcherServlet.java

    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        for (HandlerAdapter ha : this.handlerAdapters) {
            if (logger.isTraceEnabled()) {
                logger.trace("Testing handler adapter [" + ha + "]");
            }
            if (ha.supports(handler)) {
                return ha;
            }
        }
        throw new ServletException("No adapter for handler [" + handler +
                "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    }    

該getHandlerAdapter函數的功能爲:判斷private List<HandlerAdapter> handlerAdapters;中哪個Adapter能支持這個handler。或者說,這個handler應該與哪個Adapter進行搭檔才能正常工作。

從Debug的情況來看,如果我們採用的是@RequestMapping註解形式,則獲取到的是HandlerAdapter 是RequestMappingHandlerAdapter類的一個實例。

以下就是RequestMappingHandlerAdapter的support方法的實現,即只要此時的handler爲HandlerMethod的實例,就是支持的。

    AbstractHandlerMethodAdapter.java
    public final boolean supports(Object handler) {
        return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
    }
    RequestMappingHandlerAdapter    
    protected boolean supportsInternal(HandlerMethod handlerMethod) {
        return true;
    }

分析3:執行所有註冊攔截器的preHandler方法

    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HandlerInterceptor[] interceptors = getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            for (int i = 0; i < interceptors.length; i++) {
                HandlerInterceptor interceptor = interceptors[i];
                if (!interceptor.preHandle(request, response, this.handler)) {
                    triggerAfterCompletion(request, response, null);
                    return false;
                }
                this.interceptorIndex = i;//interceptorIndex標示着攔截器數組中下標小於等於interceptorIndex的攔截器已經被成功執行。
            }
        }
        return true;
    }

該函數的功能爲:調用所有註冊攔截器的preHandle方法,如果preHandle方法的返回結果爲true,則會繼續執行下面的程序。如果preHandler方法返回false,則調用triggerAfterCompletion方法。該方法的代碼如下:

    void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
            throws Exception {

        HandlerInterceptor[] interceptors = getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            for (int i = this.interceptorIndex; i >= 0; i--) {
                HandlerInterceptor interceptor = interceptors[i];
                try {
                    interceptor.afterCompletion(request, response, this.handler, ex);
                }
                catch (Throwable ex2) {
                    logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
                }
            }
        }
    }

從代碼中可以看到:triggerAfterCompletion方法它會調用所有已經成功執行的攔截器的afterCompletion方法,而且是反序調用的過程。

以上可以得到的結論爲:

1)只有所有註冊的攔截器都執行成功,即都返回true,則doDispathcer中的代碼纔會繼續執行。

2)如果第i個攔截器返回false,則會觸發triggerAfterCompletion方法來反序執行剛剛所有已經成功執行的攔截器的afterCompletion方法。並返回false從而使得doDispatcher中的代碼就不會往下執行了。

看到這裏,我們也就明白了攔截器的作用。

分析4:倒序執行所有註冊攔截器的postHandler方法

    void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
        HandlerInterceptor[] interceptors = getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            for (int i = interceptors.length - 1; i >= 0; i--) {
                HandlerInterceptor interceptor = interceptors[i];
                interceptor.postHandle(request, response, this.handler, mv);
            }
        }
    }

該函數的功能:反序執行所有註冊的攔截器的postHandler方法,比較簡單哈。

小結

就這樣我們稍微理清了下doDispatch這個方法的基本思路,有很多細節,博文中並沒有關注,如果你有興趣,可以仔細研究。

========================漂亮的分割線========================

博文的以上部分可以看作是SpringMVC用於處理Http請求的運行主線的源碼分析。而沒有分析初始化主線。在看了這篇博文之後(http://downpour.iteye.com/blog/1341459),感覺對SpringMVC的初始化主線又多了一份瞭解。

總結如下:

1、基於框架所編寫的應用程序的構成三要素。

a)入口程序DispatcherServlet,在web.xml文件中定義。

b)核心配置文件,[servlet-name]-servlet.xml文件。裏面定義了相關組件。

c)控制邏輯,Controller。

2、框架的具體實現。

有兩條主線。

a)初始化主線 -- 負責對SpringMVC的運行要素進行初始化。

b)用於處理http請求的運行主線 -- 負責對SpringMVC中的組件進行邏輯調度完成對Http請求的處理。

這兩條主線的劃分是根據servlet中的init方法和service方法來的,這兩個方法的運行時間和觸發條件截然不同。其中,init方法在整個系統啓動時運行,且只運行一次。因此,在init方法中我們往往會對整個應用程序進行初始化操作。而service方法在整個系統運行的過程中一直處於監聽模式,偵聽並處理所有的web請求。

SpringMVC的整個運行體系,是由DispatcherServlet、組件和容器這三者共同構成的。 既然是三個元素之間的關係表述,我們必須以兩兩關係的形式進行歸納:

DispatcherServlet - 容器 —— DispatcherServlet負責對容器進行初始化,初始化的依據是核心配置文件

容器 - 組件 —— 容器對組件進行全局管理

DispatcherServlet - 組件 —— DispatcherServlet對組件進行邏輯調用

2.1)初始化主線。

首先要明確3個觀點。

a)初始化主線的驅動方法:init().

b) 初始化主線的執行次序(根據DispatcherServlet的繼承結構而來):HttpServletBean–>FrameworkServlet–>DispatherServlet.

c) 初始化主線的操作對象:Spring容器(WebApplicatonContext)以及組件.

(配圖)

2.2)用於處理http請求的運行主線。

(配圖)

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