【閱讀SpringMVC原始碼】手把手帶你debug驗證SpringMVC執行流程

一樂樂發表於2022-03-09

✿ 閱讀原始碼思路:

先跳過非重點,深入每個方法,進入的時候可以把整個可以理一下方法的執行步驟理一下,也可以,理到某一步,繼續深入,回來後,接著理清除下面的步驟。



✿ 閱讀本文的準備工作,預習一下SpringMVC的執行流程

■ 解釋一下,為什麼標題是驗證SpringMVC執行流程:

      不知道小夥伴有沒有做過物理實驗的驗證實驗,道理是一樣的,舉個高中生都做過的物理實驗吧----自由落體實驗,這個實驗是通過小鋼球做拋物運動,驗證重力加速度的g值是9.8。對於本文,我們的做法是通過除錯來驗證SpringMVC的執行流程是:

1、前端控制器接收到客戶端的請求後,通過處理器對映器handlerMappings,根據路徑urlPath去匹配選擇處理器handler,最終返回一個處理器執行鏈物件HandlerExcutionChain。


2、前端控制器通過處理器介面卡,呼叫處理器的方法,然後處理器執行後返回模型檢視物件給處理器介面卡,介面卡再將模型檢視物件返回給前端物件。


3、前端控制器通過檢視解析器,將模型檢視進行解析,然後將模型資料填充到View,並渲染到檢視,然後返回響應。


? SpirngMVC執行流程圖(圖片來源於叩丁狼)

image




一、執行流程前的次要原始碼

● 開始debug的時候,對HttpMethod感到好奇,點進去檢視一下HttpMethod究竟是何物?

image

  • HttpMethod 是請求方法的列舉類,結合我們瀏覽器位址列的引數是直接輸入,可以知道我們的HttpMethod的值是Get
    image

  • 果然我們的HttpMethod的值是Get,所以下一步會執行super.service(request, response);

  • ctr進入該方法看一下,究竟是何物,發現按ctr沒有反應解決:重新開啟該類的檔案
    image

  • 進入super.service(request, response);內部一探究竟:

  • 發現這個service方法做的是請求分發操作,結合我們的請求方法是GET,所以下一步我們是到doGet方法去一探究竟~
    image

  • 再進入processRequest方法~
    image

  • 進入發現重點是doService(request, response);那我們就進入該方法內部一探究竟吧~
    image

  • 進入發現重點是doDispatch(request, response);那我們就進入該方法內部一探究竟吧~
    image




二、真正的springMVC執行流程的原始碼分析

1、驗證:前端控制器接收到客戶端的請求後,通過處理器對映器handlerMappings,根據路徑urlPath去匹配選擇處理器handler,最終返回一個處理器執行鏈物件HandlerExcutionChain。


● 獲取處理器對映器返回處理器執行鏈物件,getHandler(processedRequest);方法

我們提前瞭解到的springMVC的執行過程:前端控制器接收請求,通過處理器對映器尋找處理器,返回一個處理器執行鏈物件】。

image

● 發現了 this.handlerMappings 處理器對映器-觀察它的值為:

[org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping@40851021]【我們提前瞭解到的springMVC的執行過程:前端控制器接收請求,通過處理器對映器尋找處理器,返回一個處理器執行鏈物件】。
image

● 進入 mapping.getHandler(request); 方法內部:

image

● 進入返回處理器物件的getHandlerInternal方法內部:Object handler = lookupHandler(lookupPath, request);

我們提前瞭解到的springMVC的執行過程:前端控制器接收請求,通過處理器對映器依據路徑進行匹配來尋找處理器,返回一個處理器執行鏈物件】。
image

● 進入lookupHandler方法內部:驗證了通過處理器對映器依據路徑進行匹配來尋找處理器。還觀察到urlPath的值,正是我們配置的處理器的路徑

image
image


---- 按照閱讀原始碼觀察步驟,到這一步,你已經理清楚了,可以除錯回去,回去到:

image
......


✿ 至此,驗證了SpringMVC的執行流程:前端控制器接收到客戶端的請求後,通過處理器對映器handlerMappings,根據路徑urlPath去匹配選擇處理器handler,最終返回一個處理器執行鏈物件HandlerExcutionChain。




2、驗證:前端控制器通過處理器介面卡,呼叫處理器的方法,然後處理器執行後返回模型檢視物件給處理器介面卡,介面卡再將模型檢視物件返回給前端物件.


● 獲取處理器介面卡物件HandlerAdapter

image

● 進入getHandlerAdapter獲取處理器介面卡方法內部:

看到了this.handlerAdapters 處理器對映器-觀察它的值為:
[org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter@60038152]
image

  • 非重點:判斷與“被修改”相關的
  • 非重點:前置攔截器相關的
    image

● 進入ha.handle方法內部觀察:

image

  • 看到了(Controller) handler -觀察它的值為:
    com.shan.hello.HelloController@591b274

image

image

  • `執行完((Controller) handler).handleRequest(request, response);即呼叫我們自己書寫的處理器類的方法~``

  • 返回,繼續觀察,發現ModelAndView物件,觀察它的值
    ModelAndView [view="/WEB-INF/views/welcome.jsp"; model={msg=你好,easyMVC}]
    image

  • 這個深入進去,設定檢視名稱
    image

  • 非重點:後置攔截器
    image

  • 繼續觀察---觀察到:處理分發的結果,深入進去觀察:
    image

  • 非重點:錯誤異常相關的

  • 重點:渲染方法
    image

。。。。。。跟檢視有關的重點。。。。。


至此,驗證了SpringMVC的執行流程:前端控制器通過處理器介面卡HandlerAdapter,呼叫處理器HelloController的方法,然後處理器執行後返回模型檢視物件ModelAndView給處理器介面卡,介面卡再將模型檢視物件返回給前端控制器.




3、驗證:前端控制器通過檢視解析器,將模型檢視進行解析,然後將模型資料填充到View,並渲染到檢視,然後返回響應.


  • 非重點:國際化
  • 非重點:檢視名稱
    image

● 重點:渲染檢視

image
image

  • 觀察到返回一個模型物件,根據方法呼叫的先後順序,先呼叫了view.render(mv.getModelInternal(), request, response);的mv.getModelInternal()方法,需要重新深入一次
    image
    image

● 在渲染檢視render方法內部,觀察到mergedModel,觀察它的值:

{msg=你好,easyMVC}
image

  • 非重點:預響應

● 重點:renderMergedOutputModel【符合我們提前瞭解的SpringMVC的執行流程中渲染檢視的資料

image

● 深入,發現是將共享資料設定到請求中去

image

● 接著往下,跳過非重點,來到請求轉發

image


至此,驗證:前端控制器通過檢視解析器,將模型檢視進行解析,然後將模型資料填充到View,並渲染到檢視,然後返回響應.



相關文章