動態

詳情 返回 返回

Spring MVC執行流程及源碼詳解 - 動態 詳情

Spring MVC中各組件初始化過程已在上篇分享:初始化過程


一、SpringMVC常用組件

  • DispatcherServlet:前端控制器,統一處理請求和響應,整個流程控制的中心,由它調用其它組件處理用户的請求
  • HandlerMapping:處理器映射器,根據請求的url、method等信息查找Handler,即控制器方法
  • Handler:處理器,在DispatcherServlet的控制下Handler對具體的用户請求進行處理
  • HandlerAdapter:處理器適配器,通過HandlerAdapter對處理器(控制器方法)進行執行
  • ViewResolver:視圖解析器,不需要工程師開發,由框架提供,進行視圖解析
  • View:視圖 將模型數據通過頁面展示給用户

二、DispatcherServlet(前端控制器)的繼承結構

IDEA中快捷鍵Ctrl+Shift+Alt+U 可查看繼承圖
在這裏插入圖片描述

graph TD
A[Servlet]
A==>B[GenericServlet]
B==>C[HttpServlet]
C==>D[HttpServletBean]
D==>E[FrameworkServlet]
E==>F[DispatcherServlet]
從上圖中可以看到DispatcherServlet的頂層接口是Servlet

三、調用組件處理請求過程

$\color{#F00}{雖然我們看的是不同類中的調用過程,如果通過繼承或者實現放到同一個類中}$
$\color{#F00}{其實我們就是在同一個類中來查看方法的調用。}$

1.Servlet接口

從Servlet接口開始步步分析,在Servlet接口中存在下圖中的5種抽象方法。
快捷鍵: Alt+7
在這裏插入圖片描述

用户每次發送請求時,Servlet容器都會調用service()方法對請求進行處理
public interface Servlet {
        public void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException;   
}

2.GenericServlet抽象類

public abstract class GenericServlet implements Servlet, ServletConfig,
        java.io.Serializable {
        
     //可以看到並沒有對Servlet中的service()方法進行實現
    @Override
    public abstract void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException;

}
GenericServlet沒有對Servlet中的service()方法進行實現,那麼根據繼承結構繼續向下梳理

3.HttpServle抽象類

在這裏插入圖片描述

可以看到又調用了service(request, response)方法,如下圖

在這裏插入圖片描述請求方式有以下幾種
在這裏插入圖片描述

根據req.getMethod()獲取請求方式調用對應的doGet,doPut等等方法,繼續向下看

4.HttpServletBean抽象類

在這裏插入圖片描述

可以發現HttpServletBean沒有重寫service()方法,用的是父類HttpServle中的方法

5.FrameworkServlet抽象類

![在這裏插入圖片描述](https://img-blog.csdnimg.cn/e42a04e71e684e708e1a12c4ce6e784d.png]

FrameworkServlet中重寫了doGet等方法,則使用本類中重寫後的方法

在這裏插入圖片描述

可以看到無論service中的那個邏輯,都執行processRequest(request, response)方法,所以我們只需查看該方法即可

在這裏插入圖片描述![在這裏插入圖片描述](https://img-blog.csdnimg.cn/3ce0b0adca6e494eae4da81782bfa8a1.png]

6.DispatcherServlet類

6.1執行流程圖

為什麼説doDispatcher()是整個流程控制的中心,由它調用其它組件處理用户的請求? 那麼看下文流程即可明白
用户向服務器發送請求,請求被SpringMVC 前端控制器 DispatcherServlet捕獲。

在這裏插入圖片描述

執行流程圖大家可以對照圖來看接下來的流程

6.2圖中第的2,3步處理器映射器

就是這一步返回處理器執行鏈包含攔截器
在這裏插入圖片描述

在這裏插入圖片描述

當前類重寫了父類中的doservice()方法,又發現該方法的核心是doDispatcher方法,重點來了我們來看該方法實現

在這裏插入圖片描述在這裏插入圖片描述

6.3圖中第的4,5,6,7步處理器適配器

在這裏插入圖片描述

1.包含攔截器的執行邏輯
接下來就到攔截器的前置方法,首先看下攔截器的執行順序,方便理解接下來的代碼流程

在這裏插入圖片描述在這裏插入圖片描述請欣賞源碼流程:緊接上圖中的適配器方法

在這裏插入圖片描述攔截器的前置方法對應上圖的邏輯處理(對上圖詳解)

在這裏插入圖片描述

正序下來是實際調用處理程序方法 返回ModelAndView對象

在這裏插入圖片描述攔截器的後置方法
在這裏插入圖片描述

6.4圖中第的8,9,10

在這裏插入圖片描述>進入該方法查看
在這裏插入圖片描述看攔截器的最後執行方法

在這裏插入圖片描述

返回用户

五、總結

1.簡單總結

1. Spring MVC所有的請求都經過DispatcherServlet來統一分發。DispatcherServlet將請求分發給Controller之前,需要藉助於Spring MVC提供的HandlerMapping定位到具體的Controller。
2. HandlerMapping接口負責完成客户請求到Controller映射。
3. Controller接口將處理用户請求,這和Java Servlet扮演的角色是一致的。一旦Controller處理完用户請求,則返回ModelAndView(數據和視圖)對象給DispatcherServlet前端控制器。從宏觀角度考慮,DispatcherServlet是整個Web應用的控制器;從微觀考慮,Controller是單個Http請求處理過程中的控制器,而ModelAndView是Http請求過程中返回的模型(Model)和視圖(View)。
4.返回的視圖需要通過ViewResolver接口(視圖解析器)在Web應用中負責查找View對象,從從而將相應結果渲染給客户。

2.詳細總結

1. 用户向服務器發送請求,請求被SpringMVC 前端控制器 DispatcherServlet捕獲
2. DispatcherServlet對請求URL進行解析,得到請求資源標識符(URI),判斷請求URI對應的映射
3. 根據該URI,調用HandlerMapping獲得該Handler配置的所有相關的對象(包括Handler對象以及Handler對象對應的攔截器),最後以HandlerExecutionChain執行鏈對象的形式返回。
4. DispatcherServlet 根據獲得的Handler,選擇一個合適的HandlerAdapter。
5. 如果成功獲得HandlerAdapter,此時將開始執行攔截器的preHandler(…)方法【正向】
6. 提取Request中的模型數據,填充Handler入參,開始執行Handler(Controller)方法,處理請求。在填充Handler的入參過程中,根據你的配置,Spring將幫你做一些額外的工作:

6.1. HttpMessageConveter: 將請求消息(如Json、xml等數據)轉換成一個對象,將對象轉換為指定的響應信息
6.2 HttpMessageConveter: 將請求消息(如Json、xml等數據)轉換成一個對象,將對象轉換為指定的響應信息
6.3 數據轉換:對請求消息進行數據轉換。如String轉換成Integer、Double等
6.4 數據格式化:對請求消息進行數據格式化。 如將字符串轉換成格式化數字或格式化日期等
6.5 數據驗證: 驗證數據的有效性(長度、格式等),驗證結果存儲到BindingResult或Error中

7. Handler執行完成後,向DispatcherServlet 返回一個ModelAndView對象。
8. 此時將開始執行攔截器的postHandle(...)方法【逆向】。
9. 根據返回的ModelAndView(此時會判斷是否存在異常:如果存在異常,則執行HandlerExceptionResolver進行異常處理)選擇一個適合的ViewResolver進行視圖解析,根據Model和View,來渲染視圖。
10. 渲染視圖完畢執行攔截器的afterCompletion(…)方法【逆向】。
11. 將渲染結果返回給客户端。

Add a new 評論

Some HTML is okay.