概述
DispatcherServlet是SpringMVC的核心分發器,它實現了請求分發,是處理請求的入口,本篇將深入源碼分析它的請求分發過程。
源碼分析
進入主題前,回顧一下DispatcherServlet的繼承關系圖。
Servlet在service方法中進行請求接收與分發,DispatcherServlet的service方法繼承自HttpServlet,具體代碼如下圖所示。
在FrameworkServlet中對這個protected修飾的service方法進行了重寫,重寫的目的是支持PATCH方式請求,具體代碼如下圖所示。
上述分析中的doGet、doPost等方法在HttpServlet中沒有實際可用的實現,如果要使用這些方法,子類需要重寫這些方法,DispatcherServlet沒有重寫這些方法,在DispatcherServlet的父類FrameworkServlet中進行了重寫,看幾個重寫后的方法代碼。
可以看到這些請求都會進入當前FrameworkServlet類的processRequest方法進行處理,具體代碼如下圖所示。
FrameworkServlet中的doService是一個抽象方法,DispatcherServlet重寫了這個方法,具體代碼如下圖。
進入doDispatch方法,這個方法實現了將請求分發到具體Handler、執行攔截器的preHandle方法、調用Handler(編寫的Controller)處理具體邏輯、執行攔截器的postHandle方法、處理返回的ModelAndView或異常、執行攔截器的afterCompletion方法,具體代碼如下。
上圖描述中的HandlerMethod和HandlerExecutionChain代碼如下所示。
總結
首先,SpringMVC框架在啟動的時候會遍歷Spring容器中的所有bean,對標注了@Controller或@RequestMapping注解的類中方法進行遍歷,將類和方法上的@RequestMapping注解值進行合并,使用@RequestMapping注解的相關參數值(如value、method等)封裝一個RequestMappingInfo,將這個Controller實例、方法及方法參數信息(類型、注解等)封裝到HandlerMethod中,然后以RequestMappingInfo為key,HandlerMethod為value存到一個以Map為結構的handlerMethods中。
接著,將@RequestMapping注解中的value(即請求路徑)值取出,即url,然后以url為key,以RequestMappingInfo為value,存到一個以Map為結構的urlMap屬性中。
客戶端發起請求的時候,根據請求的URL到urlMap中查找,找到RequestMappingInfo,然后根據RequestMappingInfo到handlerMethods中查找,找到對應的HandlerMethod,接著將HandlerMethod封裝到HandlerExecutionChain;接著遍歷容器中所有HandlerAdapter實現類,找到支持這次請求的HandlerAdapter,如RequestMappingHandlerAdapter,然后執行SpringMVC攔截器的前置方法(preHandle方法),然后對請求參數解析及轉換,然后(使用反射)調用具體Controller的對應方法返回一個ModelAndView對象,執行攔截器的后置方法(postHandle方法),然后對返回的結果進行處理,最后執行afterCompletion方法。