1. 程式人生 > 實用技巧 >SpringMVC框架原始碼解析

SpringMVC框架原始碼解析

這篇blog是學完itheima視訊後進一步學習的內容,所以也是緊接著上一篇blog:
https://blog.csdn.net/qq_43175022/article/details/108933556

原始碼分析

雷豐陽大神講解https://www.bilibili.com/video/BV1d4411g7tv?p=156

元件解析 的前四步及九大元件
  1. p156 流程分析

在這裡插入圖片描述

  1. p157 -160 doDispatch()方法原始碼分析SpringMVC載入過程,對應上文元件解析前7個步驟的內容
  • 157 原始碼分析,找到有用方法加註解
  • 158 文字概述上述過程:

在這裡插入圖片描述

​ 解析getHandler()方法,引出:getHandler()方法如何根據當前請求找到對應類來處理,即如何返回目標處理類的執行鏈(同組件解析的第③步)

​ 解決:通過呼叫HandlerMapping(處理器對映器)儲存每一個處理器對應處理的請求對映資訊

  • 159 解析getHandlerAdapter()方法,解析如何找到介面卡Adapter,對應④⑤步

    三種返回值型別的獲取方法:

    HTTPRequestHandlerAdapter()、

    SimpleControllerHandlerAdapter()、

    AnnotationMethodHandlerAdapter()註解介面卡,重點

  • 160 後續Debug走完元件解析的後續兩步

  1. p161 SpringMVC九大元件:

在這裡插入圖片描述

在這裡插入圖片描述

在這裡插入圖片描述

(沒有翻譯的那個不重要),九大元件作用及共同點:

在這裡插入圖片描述

  1. p162 九大元件初始化細節:

在這裡插入圖片描述

細節:

在這裡插入圖片描述

例如HandlerMapping元件:

在這裡插入圖片描述

總結:

在這裡插入圖片描述

元件解析中的關鍵點Handler處理 P163-167
  1. p163 聚焦元件解析中⑤⑥步中Handler的目標方法執行:

在這裡插入圖片描述

在這裡插入圖片描述

在這裡插入圖片描述

引出真正執行的方法:

在這裡插入圖片描述

  1. 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標註的方法提前執行並且把執行後的返回值放在隱含模型中

  1. p165 166 上文有提及,40點只是獲取了34點的兩個提前註解的引數資訊,所以需要再次呼叫resolveHandlerArguments()方法,獲取其他引數的值
  • 165 @RequestParam的普通型別、普通型別、map型別的三個引數獲得流程:

    在這裡插入圖片描述

  • 166 POJO型別(自定義型別)引數:

    • 有註解:

      在這裡插入圖片描述

    • 沒註解:

      在這裡插入圖片描述

    總結:

    在這裡插入圖片描述

    步驟:

    • 該方法的內迴圈的一個分支語句,確定上述值:

      在這裡插入圖片描述

    • 進入resolveModelAttribute()方法獲取WebDataBinder例項物件:

      在這裡插入圖片描述

    • 標紅部分講解,確定POJO的值:

      在這裡插入圖片描述

  1. 上述166 167Handler處理獲得引數過程總結(排除兩個提前註解過程):

    在這裡插入圖片描述

    在這裡插入圖片描述

元件解析的檢視解析部分(最後三步)原始碼分析
  1. 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

略。