為什麼都說DispatcherServlet是Spring MVC的核心呢?
- 2020 年 3 月 27 日
- 筆記
# 前言
SpringMVC是目前主流的Web MVC框架之一。
本文將分析SpringMVC的核心分發器DispatcherServlet的初始化過程以及處理請求的過程,讓讀者了解這個入口Servlet的作用。
# DispatcherServlet初始化過程
在分析DispatcherServlet之前,我們先看下DispatcherServlet的繼承關係。

HttpSerlvetBean繼承自HttpServlet。
HttpServletBean覆寫了init方法,對初始化過程做了一些處理。我們來看下init方法到底做了什麼:

<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springConfig/dispatcher-servlet.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
比如上面這段配置,傳遞了contextConfigLocation參數,之後構造BeanWrapper,這裡使用BeanWrapper,有2個理由:
1. contextConfigLocation屬性在FrameworkServlet中定義,HttpServletBean中未定義
2. 利用Spring的注入特性,只需要調用setPropertyValues方法就可將contextConfigLocation屬性設置到對應實例中,也就是以依賴注入的方式初始化屬性。
然後設置DispatcherServlet中的contextConfigLocation屬性(FrameworkServlet中定義)為web.xml中讀取的contextConfigLocation參數,該參數用於構造SpringMVC容器上下文。
下面看下FrameworkServlet這個類,FrameworkServlet繼承自HttpServletBean。
首先來看下該類覆寫的initServletBean方法:

接下來看下initWebApplicationContext方法的具體實現邏輯:


這裡的根上下文是web.xml中配置的ContextLoaderListener監聽器中根據
contextConfigLocation路徑生成的上下文。<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springConfig/applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
比如這段配置文件中根據classpath:springConfig/applicationContext.xml下的xml文件生成的根上下文。
最後看下DispatcherServlet。
DispatcherServlet覆寫了FrameworkServlet中的onRefresh方法:

很明顯,initStrategies方法內部會初始化各個策略接口的實現類。
總結一下各個Servlet的作用:
1. HttpServletBean
主要做一些初始化的工作,將web.xml中配置的參數設置到Servlet中。比如servlet標籤的子標籤init-param標籤中配置的參數。
2. FrameworkServlet
將Servlet與Spring容器上下文關聯。其實也就是初始化FrameworkServlet的屬性webApplicationContext,這個屬性代表SpringMVC上下文,它有個父類上下文,既web.xml中配置的ContextLoaderListener監聽器初始化的容器上下文。
3. DispatcherServlet
初始化各個功能的實現類。比如異常處理、視圖處理、請求映射處理等。
# DispatcherServlet處理請求過程
在分析DispatcherServlet處理請求過程之前,我們回顧一下Servlet對於請求的處理。
HttpServlet提供了service方法用於處理請求,service使用了模板設計模式,在內部對於http get方法會調用doGet方法,http post方法調用doPost方法………..

進入processRequest方法看下:


其中註冊的監聽器類型為ApplicationListener接口類型。
繼續看DispatcherServlet覆寫的doService方法:

最終就是doDispatch方法。
doDispatch方法功能簡單描述一下:
首先根據請求的路徑找到HandlerMethod(帶有Method反射屬性,也就是對應Controller中的方法),然後匹配路徑對應的攔截器,有了HandlerMethod和攔截器構造個HandlerExecutionChain對象。HandlerExecutionChain對象的獲取是通過HandlerMapping接口提供的方法中得到。有了HandlerExecutionChain之後,通過HandlerAdapter對象進行處理得到ModelAndView對象,HandlerMethod內部handle的時候,使用各種HandlerMethodArgumentResolver實現類處理HandlerMethod的參數,使用各種HandlerMethodReturnValueHandler實現類處理返回值。最終返回值被處理成ModelAndView對象,這期間發生的異常會被HandlerExceptionResolver接口實現類進行處理。
# 總結
本文分析了SpringMVC入口Servlet -> DispatcherServlet的作用,其中分析了父類HttpServletBean以及FrameworkServlet的作用。
SpringMVC的設計與Struts2完全不同,Struts2採取的是一種完全和Web容器隔離和解耦的機制,而SpringMVC就是基於最基本的request和response進行設計。
文中難免有錯誤,希望讀者能夠指明出來。
# 參考資料
- http://my.oschina.net/lichhao/blog/102315
- http://my.oschina.net/lichhao/blog/104943
- http://jinnianshilongnian.iteye.com/blog/1602617