SpringMVC框架原始碼解析
這篇blog是學完itheima視訊後進一步學習的內容,所以也是緊接著上一篇blog:
https://blog.csdn.net/qq_43175022/article/details/108933556
原始碼分析
雷豐陽大神講解https://www.bilibili.com/video/BV1d4411g7tv?p=156
元件解析 的前四步及九大元件
- p156 流程分析
- p157 -160 doDispatch()方法原始碼分析SpringMVC載入過程,對應上文元件解析前7個步驟的內容
- 157 原始碼分析,找到有用方法加註解
- 158 文字概述上述過程:
解析getHandler()方法,引出:getHandler()方法如何根據當前請求找到對應類來處理,即如何返回目標處理類的執行鏈(同組件解析的第③步)
解決:通過呼叫HandlerMapping(處理器對映器)儲存每一個處理器對應處理的請求對映資訊
-
159 解析getHandlerAdapter()方法,解析如何找到介面卡Adapter,對應④⑤步
三種返回值型別的獲取方法:
HTTPRequestHandlerAdapter()、
SimpleControllerHandlerAdapter()、
AnnotationMethodHandlerAdapter()註解介面卡,重點
-
160 後續Debug走完元件解析的後續兩步
- p161 SpringMVC九大元件:
(沒有翻譯的那個不重要),九大元件作用及共同點:
- p162 九大元件初始化細節:
細節:
例如HandlerMapping元件:
總結:
元件解析中的關鍵點Handler處理 P163-167
- p163 聚焦元件解析中⑤⑥步中Handler的目標方法執行:
引出真正執行的方法:
- p164 invokeHandlerMethod()方法解析,真正執行目標方法的兩個註解(34點)的解析:
-
首先查詢34點中的是否有@SessionAttributes儲存Session,沒有直接執行下一步:
-
進入@ModelAttribute註解解析細節:
-
進入resolveHandlerArguments()方法,獲得agrs[]:
- 該方法使用一個雙層for()迴圈確定:
- 然後進行分支判斷找到的註解個數(由於上述註解衝突只能標一個,出現多個就丟擲異常):
- 分析沒有找到註解的分支:
-
進入resolveCommonArgument()方法解析普通引數(原生API):
確定當前引數是否為Servlet原生API,解析成功就將方法返回的Object賦予上文宣告的args[]
-
不為普通引數時:
本例中為map引數,所以傳入隱含模型
-
獲得args[] (該args只獲得ModelAttribute註解這一個引數)後,尋找ModelAttribute註解屬性Value的值,賦予attrName
-
反射Method型別的attributeMethodToInvoke(由for迴圈迭代遍歷獲得的attributeMethod解析而來),使其可訪問
-
執行ModelAttribute提前執行的方法(詳情可見34點)賦予一個Object型別
-
判斷上述attrName是否為空
-
不為空上述方法已經賦值
-
為空執行下列語句:
賦予ModelAttribute方法的返回值型別首字母小寫(由attributeMethodToInvoke獲得)
-
-
判斷隱含模型是否包含attrName,沒有就執行:
作用:
-
再次呼叫resolveHandlerArguments()方法,獲得agrs[]:
不同的是第一個形參換成了 invokeHandlerMethod()方法的第一個形參handleMethod解析獲得的handlerMethodToInvoke
-
return語句:
真真正正的執行方法:handlerMethodToInvoke.invoke
總結:ModelAttribute標註的方法提前執行並且把執行後的返回值放在隱含模型中
- p165 166 上文有提及,40點只是獲取了34點的兩個提前註解的引數資訊,所以需要再次呼叫resolveHandlerArguments()方法,獲取其他引數的值
-
165 @RequestParam的普通型別、普通型別、map型別的三個引數獲得流程:
-
166 POJO型別(自定義型別)引數:
-
有註解:
-
沒註解:
總結:
步驟:
-
該方法的內迴圈的一個分支語句,確定上述值:
-
進入resolveModelAttribute()方法獲取WebDataBinder例項物件:
-
標紅部分講解,確定POJO的值:
-
-
上述166 167Handler處理獲得引數過程總結(排除兩個提前註解過程):
元件解析的檢視解析部分(最後三步)原始碼分析
- p172 檢視解析流程:
結合程式碼重點摘要:
上述圖片流程解析:
完成了上文Handler處理獲得ModelAndView物件後,繼續向下執行呼叫了上述第2點processDispatchResult()方法,該方法方法體中呼叫了第3點的render()方法渲染頁面,該方法中宣告View(頁面)物件,View呼叫前端控制器定義的resolveNameView()方法,獲得一個View物件,提出下面第5點問題:
-
元件解析中的⑧⑨步的檢視解析器呼叫原始碼流程解析:
-
在前端控制器的resolveNameView()方法中,迭代遍歷九大元件之一的ViewResolver物件
過程中還檢視當前viewResolver物件的獲得方法和預設值
-
迭代出的當前頁面的檢視解析器呼叫本身介面自帶的內部resolveNameView()方法,獲得一個View物件:
進入該resolveViewName()方法(在一個抽象類中):
-
首先檢視快取,有就直接獲取
-
為空時呼叫createView()方法建立View物件:
View物件:
進入createView()方法:
-
三個不同型別的分支結構判斷建立獲得其中一種View物件:
-
呼叫父類執行建立,父類再呼叫loadView()方法一頓解析,期間又會返回createView()方法所在類進行解析(略)
-
-
獲得一個View物件
本案例中獲得了一個InternalResourceView物件
還有一個常用的View物件:RedirectView物件
-
存入快取
-
-
上述流程總結:
-
-
元件解析中的⑩步的檢視解析器呼叫原始碼流程解析:
上述得到View物件後返回第三點的render()方法(前端控制器定義的)
-
view物件呼叫介面自帶的內部render()方法(抽象類中)(上文介面圖示可見該方法):
-
進入renderMergedOutputModel()方法:
其中的關鍵方法exposeModelAsRequestAttribute():
-
進入exposeModelAsRequestAttribute()方法:
-
回到renderMergedOutputModel()方法:
取得對映地址並獲得轉發器:
轉發器轉發:
如果獲得的View物件是RedirectView物件,就是獲得重定向器,重定向到對映地址。
-
-
總結:
攔截器和異常處理原始碼 P211 212和P221 226 4P
略。