SpringMVC是目前J2EE平臺的主流Web框架,不熟悉的園友能夠看SpringMVC源碼閱讀入門,它交代了SpringMVC的基礎知識和源碼閱讀的技巧html
本文將介紹SpringMVC的核心分發器DispatcherServlet,經過源碼分析DispatcherServlet的運行過程web
首先打開DispatcherServlet類繼承圖spring
能夠看到,DispatcherServlet繼承自HttpServlet,它的本質就是一個Servlet,這就是爲何上篇須要在web.xml經過url-mapping爲DispatcherServlet配置映射請求的緣由瀏覽器
咱們從HttpServletBean開始看,HttpServletBean重寫了其父類GenericServlet的init方法,咱們來看看init到底作了什麼(在啓動Tomcat的時候會進入init方法)mvc
ServletConfigPropertyValues是HttpServletBean的內部靜態類,它負責取到web.xml中contextConfigLocation,並addPropertyValue(),在PropertyValues能夠看到取到的值app
BeanWrapper是一個實體包裝類,簡單地說,BeanWrapper提供分析和操做JavaBean的方案,如值的set/get方法、描述的set/get方法以及屬性的可讀可寫性框架
ResourceLoader讀取到servletContext和classLoader,servletContext裝載了咱們剛纔的dispatcher-servlet.xml,classLoader找到咱們的字節碼文件並追蹤到咱們的jar包路徑,還有不少屬性不一一介紹,園友們能夠自行打斷點查看源碼分析
web.xml部分代碼,這就是咱們讀取的contextConfigLocationpost
<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>
回頭再看,這裏構造BeanWrapper,使用setPropertyValues設置PropertyValues,利用Spring依賴注入的特性初始化屬性,讀取web.xml的contextConfigLocation屬性用於構造Spring上下文url
用BeanWrapper的最大好處在於,咱們不須要再在HttpServletBean中定義contextConfigLocation屬性,並聲明調用set/get方法,BeanWrapper已經幫咱們作好了
按ctrl+alt+b,看initServletBean()到底在哪裏被實現
接下來,咱們看FrameworkServlet這個類,該類繼承自HttpServletBean,看FrameworkServlet的initServletBean()方法
webApplicationContext是FrameworkServlet的上下文,initWebApplicationContext()方法爲當前Servlet初始化上下文
initFrameworkServlet()交由FrameworkServlet子類實現,默認實現爲空,該方法會在bean屬性和上下文加載後被調用
咱們如今看initWebApplicationContext()方法實現
獲取根上下文,並初始化一個空的上下文
527行不會進入if,只有上下文實例在構造的時候注入纔會調用
549行調用findWebApplicationContext()方法,這個方法用來查看該Servlet是否已經設置上下文,咱們點進去看,沒有獲得attrName,返回null
當FrameworkServlet沒有上下文實例定義時,調用createWebApplicationContext(),參數是咱們在initWebApplicationContext()中獲得的rootContext(根上下文),爲FrameworkServlet初始化上下文,設置id,environment,configLocation等屬性
560行onRefresh()是爲了防止構造注入上下文的時候沒有刷新,去手動刷新,在DispatcherServlet有實現
566行爲當前Servlet設置上下文
web.xml中配置的ContextLoaderListener根據applicationContext.xml生成上下文
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springConfig/dispatcher-servlet.xml</param-value> </context-param> <!-- Bootstrap the root application context as usual using ContextLoaderListener --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
進入ContextLoaderListener,打開其父類ContextLoader,常常用SpringMVC開發的人應該對ClassPathResource比較熟悉,ClassPathResource常常被咱們用來讀取資源文件
ContextLoader162行指向了ContextLoader.properties,一個配置文件,它指向了org.springframework.web.context.support.XmlWebApplicationContext這個類
private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";
在XmlWebApplicationContext loadBeanDefinitions()獲取到了contextConfigLocation,XmlBeanDefinitionReader使用xsd讀取xml文件,再也不詳述,園友能夠點進去看看
順着剛纔的思路,咱們看看DispatcherServlet,DispatcherServlet重寫了父類FrameworkServlet的onRefresh(ApplicationContext contex)方法
總結下HttpServletBean,FrameworkServlet和DispatcherServlet初始化過程
1.HttpServletBean
初始化web.xml中的參數
2.FrameworkServlet
將上下文賦予當前Servlet
3.DispatcherServlet
初始化HandlerMapping(請求映射),HandlerExceptionResolver(異常處理),ViewResolver(視圖解析)等功能實現類
在瀏覽器輸入http://localhost:8080/springmvcdemo/employee,觸發DispatcherServlet的processRequest方法
我不得不說下其父類FrameworkServlet的processRequest方法
previousLocaleContext獲取和當前線程相關的LocaleContext
根據已有請求構造一個新的和當前線程相關的LocaleContext
previousAttributes獲取和當前線程綁定的RequestAttributes
爲已有請求構造新的ServletRequestAttributes,加入預綁定屬性
initContextHolders讓新構造的RequestAttributes和ServletRequestAttributes和當前線程綁定,加入到ThreadLocal,完成綁定
抽象方法doService由FrameworkServlet子類DispatcherServlet重寫
resetContextHolders方法解除RequestAttributes,ServletRequestAttributes和當前線程的綁定
註冊監聽事件ServletRequestHandledEvent,在調用上下文的時候產生Event
如今咱們看下DispatcherServlet的doService方法
attributesSnapshot用來保存request域中的數據,能夠叫作「快照」
進入doDispatch方法
接下來咱們看一看doDispatch方法,內容不少,我在這作些簡述,細節部分後續會逐一分析
932行checkMultipart方法將request轉化成Multipart request
936行HandlerExecutionChain獲取Handler,有攔截器、Bean、BeanFactory,並對應上請求的Controller和Service等等
943行HandlerAdapter獲取到各類argumentResolvers,用來解析參數,還能獲取到各類returnValueHandlers,用來處理類返回值(後續會詳解)
963行經過HandlerAdapter handle方法返回視圖模型ModelAndView
969行給ModelAndView設置viewName
970行使用applyPostHandle方法攔給已註冊的攔截器放行,咱們此時並無聲明攔截器,spring給咱們默認生成兩個默認已註冊的攔截器,以下
結束,文中不免有錯誤,但願園友能及時指出
https://docs.spring.io/spring/docs/4.3.7.RELEASE/spring-framework-reference/htmlsingle/#mvc-servlet