-
Spring MVC簡介
Spring MVC是目前使用的比較廣泛的一個MVC架構,通過Spring MVC可以很輕松地建構一個完整的Web應用程式。并且Spring MVC對其他的架構有很好的相容性,比如可以通過內建MyBatis架構去更好地和資料庫進行互動。一個Web應用最核心的功能就是對到來的請求進行響應,下面我們通過Spring MVC的源碼來分析下Spring MVC具體是怎樣去響應一個請求的。(Spring MVC的源碼位于Spring-framework下面的Spring-webmvc中)。
-
請求處理流程
在使用Spring MVC架構的時候,我們一般會在web.xml中配置一個DispatcherServlet作為Spring MVC的入口去映射所有的請求。DispatcherServlet的繼承關系如圖2-1所示。

圖2-1
-
Servlet
Servlet這個接口其實很簡單,裡面總共定義了5個方法,如圖3-1所示。
圖3-1
-
GenericServlet
GenericServlet是java中對Servlet的預設實作,在實作Servlet接口的同時實作了ServletConfig接口。GenericServlet的結構如圖4-1所示。
圖4-1
在GenericServlet中提供了無參的init方法。GenericServlet在類中首先實作了init(ServletConfg config)這個帶參數的init方法,如圖4-1所示。在方法中将config傳遞到了類中,這樣在類中可以直接使用ServletConfig中的各種方法。然後調用了無參的init方法,無參的init方法是一個模版方法,主要提供給子類覆寫。這樣之後的子類就可以專注于業務邏輯,進而不用再去關心對ServletConfg的處理。
圖4-2
在GenericServlet中還提供了兩個log方法,一個用于列印日志,另一個用于輸出異常。主要通過傳遞給ServletContext來實作的。
-
HttpServlet
HttpServlet顧名思義就是用Http協定實作的Servlet。HttpServlet中實作的方法如圖5-1所示。我們在自己重寫Servlet的時候一般基于這個類實作邏輯,HttpServlet幫助我們屏蔽了很多Http協定實作的具體細節。
圖5-1
HttpServlet中最主要的功能其實就是對service方法實作。在service方法中首先将ServletRequest和ServletResponse轉換成HttpServletRequest和HttpServletResponse。然後在方法中對Http的請求類型進行判斷,不同的請求類型分發給不同的方法去處理。比如Get請求分發給doGet方法處理,Post請求分發給doPost方法處理。HttpServlet中提供了七種請求類型的處理,doGet、doPost、doPut、doDelete、doOptions、doTrace、doHead。
-
HttpServletBean
在HttpServletBean類中(類中的方法如圖6-1所示),并沒有發現service方法,HttpServletBean主要的作用其實是參與了請求的建立的工作,并沒有涉及請求的處理工作。HttpServletBean在繼承了HttpServlet的同時實作了EnvironmentCapable,EnvironmentAware這兩個接口,使得HttpServletBean具有感覺以及提供Environment的能力。
圖6-1
在圖6-2中,我們可以看到HttpServletBean的init方法的具體實作,首先通過BeanWrapper設定相關的初始化屬性。然後調用initServletBean這個模版方法,子類通過這個模版方法初始化。
圖6-2
-
FrameworkServlet
從HttpServletBean中,我們可以知道它的子類也就是FrameworkServlet的初始化入口方法是initServletBean方法,通過對方法(如圖7-1)的分析可以看到,這個方法主要是完成了WebApplicationContext和FrameworkServlet的初始化工作。
圖7-1
在FrameworkServlet類中,主要重寫了service、doGet、doPost、doPut、doDelete、doOptions、doTrace方法,意味着除了doHead方法,其他的所有請求的方法都進行了重寫。對這些方法進行分析(如圖7-2),可以看到除了doOptions和doTrace方法外,FrameworkServlet将這些方法都交給了processRequest這個方法進行處理。processRequest方法是FrameworkServlet對請求進行處理的核心類。
圖7-2
在processRequest方法中對一個請求進行處理,主要有三個步驟,第一個步驟首先是在doService方法之前将目前請求的LocaleContext和ServletRequestAttributes在處理請求之前放到LocaleContextHolder以及RequestHolder,并在請求處理完成後恢複。然後調用了doService模版方法具體處理一個請求,這個方法會在接下來的DispatcherServlet中具體實作。最後在請求處理完成後恢複LocaleContext和ServletRequestAttributes以及釋出ServletRequestHandledEvent消息。
-
DispatcherServlet
DispatcherServlet是Spring MVC對請求進行處理的最核心的類。通過之前的分析可以知道,DispatcherServlet對請求處理的核心方法是doService方法。doService方法中首先判斷請求是不是一個include請求,如果是,則通過attributesSnapshot對請求的屬性進行一個備份。然後對請求設定了WebApplicationContext、localResolver、themeSource等屬性(如圖8-1所示),接下來調用doDispatch方法對請求進行一個具體的處理。最後如果這個請求是一個異步的請求,則将attributesSnapshot中儲存的值重新設定回請求中。
圖8-1
在doDispatch方法中主要完成了四件事情,首先是根據請求找到相應的Handler,然後根據Handler找到對應的HandlerAdapter,HandlerAdapter會被用于處理多種Handler,調用Handler實際處理請求的方法。最後調用processDispatchResult去找到view并渲染輸入給使用者。
-
總結
通過對上述Spring MVC處理請求涉及到的類的源碼簡單分析,我們可以對Spring MVC對請求的處理流程有一個更清楚的認識。