SpringMVC請求處理過程原始碼簡析

jinmaoxu發表於2018-09-04
  1. Spring MVC簡介

Spring MVC是目前使用的比較廣泛的一個MVC框架,通過Spring MVC可以很輕鬆地構建一個完整的Web應用程式。並且Spring MVC對其他的框架有很好的相容性,比如可以通過整合MyBatis框架去更好地和資料庫進行互動。一個Web應用最核心的功能就是對到來的請求進行響應,下面我們通過Spring MVC的原始碼來分析下Spring MVC具體是怎樣去響應一個請求的。(Spring MVC的原始碼位於Spring-framework下面的Spring-webmvc中)。

  1. 請求處理流程

在使用Spring MVC框架的時候,我們一般會在web.xml中配置一個DispatcherServlet作為Spring MVC的入口去對映所有的請求。DispatcherServlet的繼承關係如圖2-1所示。

圖2-1

圖2-1

  1. Servlet

Servlet這個介面其實很簡單,裡面總共定義了5個方法,如圖3-1所示。

圖3-1

  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來實現的。

  1. 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。

  1. HttpServletBean

在HttpServletBean類中(類中的方法如圖6-1所示),並沒有發現service方法,HttpServletBean主要的作用其實是參與了請求的建立的工作,並沒有涉及請求的處理工作。HttpServletBean在繼承了HttpServlet的同時實現了EnvironmentCapable,EnvironmentAware這兩個介面,使得HttpServletBean具有感知以及提供Environment的能力。

圖6-1

在圖6-2中,我們可以看到HttpServletBean的init方法的具體實現,首先通過BeanWrapper設定相關的初始化屬性。然後呼叫initServletBean這個模版方法,子類通過這個模版方法初始化。

圖6-2

  1. 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訊息。

  1. 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並渲染輸入給使用者。

  1. 總結

通過對上述Spring MVC處理請求涉及到的類的原始碼簡單分析,我們可以對Spring MVC對請求的處理流程有一個更清楚的認識。

 


相關文章