DispatcherServlet源碼分析


 

一、客戶端發送請求的總體過程

  DispatcherServlet是SpringMVC的入口,DispatcherServlet其實也是一個Servlet。服務器處理客戶端請求的步驟如下:

  1、客戶端發送請求的時候,會調用Servlet對應的doGet、doPost、doDelete等方法。

  2、上面的方法會調用processRequest方法

  3、processRequest方法進一步調用doService方法

  4、DispatcherServlet實現了doService方法,在doService方法中對Request參數進行處理,然后調用doDispatch方法

  5、在doDispatch方法中獲取並調用處理器映射器、處理器適配器,獲取並返回執行結果。

 

  DispatcherServlet是Web中處於比較核心的位置,被稱為前端控制器。SpringMVC中常用的幾個概念,處理器映射器(HandlerMapping)、處理器適配器(HandlerAdapter)和視圖解析器(ViewResolver)都在DispatcherServlet的doDispatch中有所體現。

  通過調用getHandler方法獲取Handler對象,getHandler方法會調用HandlerMapping,通過請求的路徑查找Handler;返回值是一個HandlerExecutionChain對象,其中不只包含了Handler對象,還包含一個HandlerInterceptor(攔截器)的鏈表。

  Handler需要借助於HandlerAdapter來執行,doDispatch調用getHandlerAdapter方法查找具體的HandlerAdapter。Spring容器中可能配置了多個HandlerAdapter,具體哪個HandlerAdapter能夠處理當前的Handler,是根據HandlerAdapter的supports方法來查找可以處理該Handler的HandlerAdapter。

  之后會調用攔截器的preHandler方法,HandlerAdapter會處理具體的Handler,調用攔截器的postHandler方法。

  然后,doDispatch會調用processDispatchResult方法,在processDispatchResult方法中,在其中的render方法中,會循環ViewResolver,確定哪個ViewResolver可以解析對應view,然后調用view的render方法進行渲染。processDispatchResult方法還會調用攔截器的afterCompletion方法。

  

二、處理器映射器

   通過調用處理器映射器,得到請求路徑對應的處理器。如果沒有找到處理器,則在Response中返回錯誤信息,該方法直接退出。

    // Determine handler for the current request.
    mappedHandler = getHandler(processedRequest, false);
    if (mappedHandler == null || mappedHandler.getHandler() == null) {
        noHandlerFound(processedRequest, response);
        return;
    }

 

  getHandler方法的代碼如下,實質就是循環便利所有處理器映射器,找到與請求路徑相匹配的處理器映射器。

    /**
     * Return the HandlerExecutionChain for this request.
     * <p>Tries all handler mappings in order.
     * @param request current HTTP request
     * @return the HandlerExecutionChain, or {@code null} if no handler could be found
     */
    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;
    }

 

 

三、判斷是否網頁是否需要重新生成

  HTTP協議允許只發送帶有Last-Modified的表頭信息到服務器端,服務器端判斷本地的信息是否修改了,如果沒修改,最后的時間將與Last-Modified一致,此時不需要服務器端再生成信息,直接告訴瀏覽器信息沒有改變,使用其本地數據即可。

  Last-Modified介紹

    // Determine handler adapter for the current request.
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

    // Process last-modified header, if supported by the handler.
    String method = request.getMethod();
    boolean isGet = "GET".equals(method);
    if (isGet || "HEAD".equals(method)) {
        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
        if (logger.isDebugEnabled()) {
            logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
        }
        if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
            return;
        }
    }

 

 

四、攔截器

  在從處理器映射器獲取對應的處理器的時候(通過DispatcherServlet的getHandler方法),返回的不是處理器對象,而是一個HandlerExecutionChain,這個HandlerExecutionChain中包含Handler對象;同時還包含一個HandlerInterceptor鏈表,而HandlerInterceptor就是攔截器。

  而對於HandlerInterceptor接口中定義的三個方法中,preHandler在handler的執行前被調用;而postHandler在handler執行后,在進行視圖解析之前執行;afterCompletion在view渲染完成、在DispatcherServlet返回之前執行。 

    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
        return;
    }

    try {
        // Actually invoke the handler.
        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    }
    finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            return;
        }
    }

    applyDefaultViewName(request, mv);
    mappedHandler.applyPostHandle(processedRequest, response, mv);

 

  上面的代碼中,mappedHandler.applyPreHandle(processedRequest, response)是執行攔截器的preHandler;而mappedHandler.applyPostHandle(processedRequest, response, mv)則執行攔截器的postHandler方法。而攔截器的afterCompletion方法則是在processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException)方法中執行的,位置是在該方法的最后,view渲染完成后。

PS:我們需要注意的是:當preHandler返回false時,當前的請求將在執行完afterCompletion后直接返回,handler也將不會執行。源碼如下:

  boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (getInterceptors() != null) {
            for (int i = 0; i < getInterceptors().length; i++) {
                HandlerInterceptor interceptor = getInterceptors()[i];
                if (!interceptor.preHandle(request, response, this.handler)) {
                    triggerAfterCompletion(request, response, null);
                    return false;
                }
                this.interceptorIndex = i;
            }
        }
        return true;
    }

   需要注意的是上面的interceptorIndex變量,它保存的是剛剛已經執行過的攔截器。而一旦攔截器的preHandler返回false,就會進入triggerAfterCompletion方法,該方法會執行攔截器的afterCompletion方法。但是不可能把所有攔截器的afterCompletion方法都執行一遍,所以使用interceptorIndex進行記錄,就可以很方便的知道都有哪些攔截器執行了preHandler方法,調用他們的afterCompletion就可以了。

  另外需要注意的地方是,設置interceptorIndex的位置是在循環的最后,也就是說,此處記錄的是preHandler返回true的那個攔截器對應的index,也就是說返回false的攔截器的afterCompletion方法不會被調用。

 

五、處理器適配器

  通過HandlerExecutionChain.getHandler返回處理器對象,getHandler返回的是Object對象。DispatcherServlet通過getHandlerAdapter方法找到與Handler匹配的HandlerAdapter類,再通過這個HandlerAdapter去執行Handler對應的方法。

獲取Handler匹配的HandlerAdapter:

  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");
    }

HandlerAdapter去執行Handler對應方法,其中返回的mv是ModelAndView對象:

    try {
        // Actually invoke the handler.
        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    }
    finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            return;
        }
    }

 

 

六、視圖解析器

  DispatcherServlet在processDispatchResult中解析並返回View,在render方法中會根據ModelAndView渲染產生View對象。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM