SpringMVC:(二)根據請求查找對應的Controller方法的流程


前言:

   在這之前我們已經建立請求和Controller方法的映射集合,接下來我們就要去取出映射關系里獲取請求的邏輯實例。

 

 根據請求查找對應的Controller方法的流程主要發生在DispatcherServlet類的doDispatch()方法。該方法的調用時機是當我們訪問路徑:http://localhost:8080/springmvcdemo/headline/open 的時候

觀察下面的流程圖我們可以看到

(1)會去訪問到DispatcherServlet的父類FrameworkServletservice()方法

(2)然后會根據請求選擇doGet()或者doPost()方法

(3)然后父類會去調用到子類DispatcherServletdoService()方法去處理邏輯

(4)DispatcherServletdoService()方法會去調用doDispatch()去派遣給Controller執行   =>  (根據請求查找對應的Controller方法)就是在該方法中調用了getHandler()去獲取的

 

 

 


 

 

這里我們重新回到RequestMappingHandlerMapping類中。

我們觀察其類圖:

 

 

 

通過觀察類圖我們發現該類還實現了HandlerMapping接口,該接口就一個getHanndler()方法。該方法只需要給其傳遞HttpServletRequest參數即可返回HandlerExecutionChain對象

HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

 

類圖上顯示HandlerMapping接口的主要實現類為:AbstractHandlerMapping類。

接下來我們跟進到AbstractHandlerMapping類的getHanndler()方法。

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        //獲取handler的具體邏輯,留給子類實現
        Object handler = getHandlerInternal(request);
        if (handler == null) {
            //如果獲取到的handler為null則采用默認的handler,即屬性defaultHandler
            handler = getDefaultHandler();
        }
        if (handler == null) {
            //如果連DefaultHandler也為空,則直接返回空
            return null;
        }
        // Bean name or resolved handler?
        //如果handler是beanName,從容器里獲取對應的bean
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = obtainApplicationContext().getBean(handlerName);
        }
        //根據handler和request獲取處理器鏈HandlerExecutionChain
        HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);//獲取到執行器鏈
   
     //下面的代碼與主要流程無關(略) if (logger.isTraceEnabled()) {logger.trace("Mapped to " + handler);} else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {logger.debug("Mapped to " + executionChain.getHandler());} if (hasCorsConfigurationSource(handler)) { CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null); CorsConfiguration handlerConfig = getCorsConfiguration(handler, request); config = (config != null ? config.combine(handlerConfig) : handlerConfig); executionChain = getCorsHandlerExecutionChain(request, executionChain, config); } return executionChain;//返回執行器鏈 }

 

(1)調用子類的getHandlerInternal()方法去獲取handler的具體邏輯(AbstractHandlerMethodMapping.getHandlerInternal()方法)

  (A)獲取到Request(請求)中的URL(用來匹配handler)

    (B)調用lookupHandlerMethod()方法,根據路徑尋找Handler,並封裝成HandlerMethod

      (a)嘗試從先前映射建立的時候存入的urlLookup中查找映射

      (b)如果匹配到了,檢查其他屬性是否符合要求,如請求方法,參數,hander等 (沒有直接匹配到,則遍歷所有的處理方法進行通配符匹配)

      (c)如果方法有多個匹配,不同的通配符等,則排序選擇出最合適的一個

      (d)如果有多個匹配的,會找到第二個最合適的進行比較。

      (e)給請求(request)設置上屬性參數

      (f)返回匹配的URL的處理的方法

    (C)根據handlerMethod中的bean來實例化Handler,並添加進HandlerMethod

(2)如果獲取到的handler為null則采用默認的handler,即屬性defaultHandler

(3)如果連DefaultHandler也為空,則直接返回空

(4)如果上面獲取到的處理方法(handler)是實現了String接口,說明其只是一個beanName,此時我們要去容器中獲取到真正對應的Bean

(5)根據處理方法(handler)和請求(request)獲取處理器鏈(HandlerExecutionChain)

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
        //判斷handler是不是執行器鏈,如果不是則創建一個執行器鏈
        HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
                (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

        String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
        //包裝攔截器
        /*可以去做一些請求的時候業余上對用戶信息的攔截
            <mvc:interceptor>
                <mvc:mapping path="/shopadmin/**" />
                    <bean id="ShopInterceptor" class="com.imooc.o2o.interceptor.shopadmin.ShopLoginInterceptor" />
            </mvc:interceptor>
         */
        for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
            if (interceptor instanceof MappedInterceptor) {
                MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
                if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                    chain.addInterceptor(mappedInterceptor.getInterceptor());
                }
            }
            else {
                chain.addInterceptor(interceptor);
            }
        }
        return chain;//將包裝好的執行器鏈返回
}

  (A)創建獲取到執行器鏈(判斷傳入的handler(處理方法)是不是執行器鏈,如果不是則創建一個執行器鏈,如果是則強轉為執行器鏈)

  (B)對獲取到的執行器鏈進行包裝攔截器(將配置好的攔截器for循環遍歷然后篩選path,如果符合當前這個執行器鏈,則對其進行包裝)

(6)無關邏輯(略)

(7)返回處理器鏈 

 


免責聲明!

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



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