這篇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()方法:
取得映射位址并獲得轉發器:
轉發器轉發:
- 總結:
攔截器和異常處理源碼 P211 212和P221 226 4P
略。