SpringMVC工作原理之參數解析

前面分析到 SpringMVC工作原理之處理映射[HandlerMapping] ,由映射處理器(HandlerMapping) 解析出對應的 handler。接著 SpringMVC工作原理之適配器[HandlerAdapter] 描述了 handler 是怎么匹配到合適的適配器,進行 handler 對應方法的執(zhí)行。其他幾種適配器還好,但是 RequestMappingHandlerAdapter 適配器對應接下來的參數解析及綁定并執(zhí)行并不是那么簡單,因此本篇筆記主要分析 RequestMappingHandlerAdapter 適配器解析對應 handler 的執(zhí)行流程。
本篇筆記主要分析SpringMVC 5.1.1 這個版本。

SpringMVC運行流程

RequestMappingHandlerAdapter 大概解析流程如下

RequestMappingHandlerAdapter解析流程

1 了解在前面

在開始下面的具體源碼分析前,我們需要了解一些相關的類和接口

1.1 HandlerMethod

在開始記錄方法執(zhí)行流程前,必須要先說下記錄方法的對象 HandlerMethodHandlerMethod 及子類主要用于封裝方法調用相關信息。簡單理解為保持方法信息的 pojo 類。

HandlerMethod及其子類.png

分析下各個類的功能及職責:

  • HandlerMethod 封裝方法定義相關的信息 (如類、方法、參數等)
  • InvocableHandlerMethod 參數準備委托 HandlerMethodArgumentResolver 進行具體的解析
  • ServletInvocableHandlerMethod 添加返回值處理職責,ResponseStatus 處理

在容器初始化的時候,RequestMappingHandlerMapping 映射處理器就將 @RequestMapping 描述的方法以 RequestMappingInfo 為 key,HandlerMethod 為 value 放進自己的緩存 。至如 HandlerMethod 內部后面是怎么進行對應方法上的參數解析及綁定到后來的方法執(zhí)行等等,咱們接下來會詳細講解。

1.2 參數解析器(HandlerMethodArgumentResolver)和返回值的解析器(HandlerMethodReturnValueHandler)

在分析源碼之前,首先讓我們來看下SpringMVC中兩個重要的接口,兩個接口都是在 3.1 版本后添加的。

  • 處理方法參數的解析器接口
  • 處理方法調用返回值的解析器接口

兩個接口分別有兩個方法,一個用來查看該解析器是否支持該參數的解析,第二個方法用來對參數進行解析。

1.3 默認解析器的注入

在容器初始話的時候,初始化 RequestMappingHandlerAdapter 適配器的時候會將默認的參數解析器都注入進緩存中。

加載默認的參數解析器(ArgumentResolvers),綁定到 RequestMappingHandlerAdapter 適配器的 argumentResolvers 屬性上。
加載默認的返回值解析器(ReturnValueHandlers),綁定到 RequestMappingHandlerAdapter 適配器的 returnValueHandlers 屬性上。

下面我們來簡單的看下都有哪些默認解析器

  • 默認注入的參數解析器
  • 默認注入的返回值解析器

2 解析過程流程

2.1 解析器的綁定及匹配

接著 RequestMappingHandlerAdapter 適配器的 handleInternal(..) 方法往下說,在 handleInternal(..) 方法中主要檢查是否需要同步執(zhí)行接下來對方法的操作,內部調用 invokeHandlerMethod(..) 方法。

該方法內部就方法執(zhí)行流程大致可以分為以上標注的 6 步:

①. 對應 WebDataBinderFactory 工廠類的創(chuàng)建,因里面涉及到的東西有點多,將放在下面參數值類型轉換部分詳細解說。
②. 根據該 HandlerMethod 創(chuàng)建對應的 ServletInvocableHandlerMethod 對象。
③. 將注入到緩存的參數解析器綁定到創(chuàng)建的 ServletInvocableHandlerMethod 對象上。
④. 將注入緩存的返回值解析器綁定到創(chuàng)建的 ServletInvocableHandlerMethod 對象上。
⑤. 將上面創(chuàng)建的 WebDataBinderFactory 工廠類對象綁定到創(chuàng)建的 ServletInvocableHandlerMethod 對象上。
⑥. 執(zhí)行 ServletInvocableHandlerMethodinvokeAndHandle(...) 方法。

總結:RequestMappingHandlerAdapter 在內部對于每個請求,都會實例化一個 ServletInvocableHandlerMethod 進行處理。

ServletInvocableHandlerMethod 內部會分別對請求跟響應進行處理。

進入執(zhí)行請求對應方法里面看看流程

接下來就是請求參數解析器和返回值解析器上場的時候了。

①. ServletInvocableHandlerMethod 類在處理參數的時候,會使用自己綁定的參數解析器,參數解析器記錄在屬性argumentResolvers (這個屬性是它的父類 InvocableHandlerMethod中定義的),argumentResolvers 屬性是一個 HandlerMethodArgumentResolverComposite 類(這里使用了組合模式的一種變形),這個類是實現了 HandlerMethodArgumentResolver 接口的類,實現了該類里面的兩個接口。同時里面有記錄所有參數解析器的 List 集合,有緩存 MethodParameter 與解析器對應關系的 Map 集合。

②. ServletInvocableHandlerMethod 類在處理返回值的時候,會使用自身綁定的返回值解析器,該解析器記錄在屬性 returnValueHandlers (自身屬性),returnValueHandlers 屬性是一個 HandlerMethodReturnValueHandlerComposite 類(這里使用了組合模式的一種變形),這個類實現了 HandlerMethodReturnValueHandler 接口,實現了該接口里面的兩個方法。同時里面有記錄所有返回值解析器的 List 集合。

2.2 參數解析器內部解析流程

因為解析器太多,這里只能抽其中一個來了解下參數解析器內部實現解析的邏輯,選個最常用的解析器 RequestParamMethodArgumentResolver,他是用來解析 @RequestParam 注解的參數。RequestParamMethodArgumentResolver 繼承自 AbstractNamedValueMethodArgumentResolver,而 AbstractNamedValueMethodArgumentResolver 抽象類實現了 HandlerMethodArgumentResolver 接口。

首先來看下其支持解析的參數種類

再來看下其解析參數的過程

參數解析的過程可以分為三個部分:參數名字解析、參數值獲取、參數值類型轉換。

(1). 參數名字解析

NamedValueInfo 是該抽象解析器定義的一個內部類,有三個屬性記錄形參上的修飾,分別是 namerequired、defaultValue,分別記錄形參名字、形參是否必須、形參默認值。

咱們來看下 RequestParamMethodArgumentResolver 子類是怎么實現 createNamedValueInfo(..) 這個方法的。

很明顯返回的是 RequestParamNamedValueInfo 對象,RequestParamNamedValueInfo 類是該解析類里面的一個內部類,繼承自 NamedValueInfo,構建方法里面將傳進去的 RequestParamname、requireddefaultValue 分別記錄到創(chuàng)建的 RequestParamNamedValueInfo 對象的屬性上。

通過后面的 updateNameValueInfo(..) 方法檢查一遍,當 @RequestParam 注解的 namevalue 屬性為空時,會自動以形參的名字作為 name

(2). 參數值獲取

resolveName(...) 抽象類的抽象方法,具體由其子類實現,下面我們來看下 RequestParamMethodArgumentResolver 解析類是怎么實現的吧。

上面分別實現了可變請求和不可變請求對于根據 name 取值的方式。

(3). 參數值類型轉換

從上面源碼可以看出,通過自身綁定的 binderFactory 創(chuàng)建出 WebDataBinder 對象,通過創(chuàng)建出來的 WebDataBinder 對象來進行數據轉換。
那么接下來的分析就有條理了,分為三個部分:WebDataBinderFactory 屬性對象的創(chuàng)建及綁定、WebDataBinderFactory 屬性對象內部執(zhí)行 createBinder(...) 方法創(chuàng)建出 WebDataBinder 對象的具體邏輯、 WebDataBinder 進行數據類型轉換的具體邏輯。

(3.1) WebDataBinderFactory 屬性對象的創(chuàng)建及綁定

前面說到在 RequestMappingHandlerAdapter 適配器中執(zhí)行 invokeHandlerMethod(...) 方法,通過 WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); 方法創(chuàng)建 WebDataBinderFactory 對象,并將其綁定在創(chuàng)建的 ServletInvocableHandlerMethod 對象上。

這里的 this.webBindingInitializer 屬性其實就是一個 ConfigurableWebBindingInitializer 對象,即在 <mvc:annotation-driven /> 時默認注冊的。即包含一些解析參數需要的 MessageCodesResolverBindingErrorProcessor、ValidatorConversionService、PropertyEditorRegistrar[]。

(3.2) WebDataBinderFactory 對象內部執(zhí)行 createBinder(...) 方法創(chuàng)建出 WebDataBinder 對象的具體邏輯

首先來看下 WebDataBinderFactory 接口的實現類

再來看 createBinder(...) 方法

1 newWebDataBinder 接口實現類,依照自身實現類為準,從 (3.1) 看出這里的 this 對象是 ServletRequestDataBinderFactory 對象,new 出來的 WebDataBinder 接口實現類應該是 ExtendedServletRequestDataBinder 類對象。

2 對 WebDataBinder 對象進行一些初始化,this.initializer 屬性是在上面 (3.1) 綁定進來的 ConfigurableWebBindingInitializer 對象。

從執(zhí)行方法里面可以看出設置一些我們在解析參數時用到的轉換器和驗證器到 WebDataBinder 對象上。

3 自身初始化 WebDataBinder 的方法

從上面 isBinderMethodApplicable(..) 匹配符合該參數轉換的 @initBinder 注解修飾的方法邏輯可以看出,以后在 Controller 里面寫 @initBinder 注解修飾的方法,盡量指定 value 屬性字段,以免每個參數解析都執(zhí)行不必要的 @initBinder 注解修飾的方法。

(3.3) WebDataBinder 進行數據類型轉換的具體邏輯,執(zhí)行convertIfNecessary(...) 方法

數據轉換這塊很復雜,我目前的能力只能做潛在的分析。因為 WebDataBinder 繼承自 DataBinder,又因為 DataBinder 實現了PropertyEditorRegistryTypeConverter 接口,所以該類具有注入自定義編輯器和轉換數據的能力。
數據的轉換最終交給 TypeConverterDelegate 類進行轉換

從上面可以看出,先匹對自定義的編輯器進行數據轉換,沒有合適的編輯器則匹配對應的轉換器進行數據轉換。
再來看下第 3 步自定義編輯器里面是怎么來轉換數據的

2.3 返回值析器內部解析流程

前面說到返回值處理器記錄在 ServletInvocableHandlerMethod 綁定的 returnValueHandlers 屬性上,returnValueHandlers 屬性是一個 HandlerMethodReturnValueHandlerComposite 類,這個類是一種組合模式的變形,他也實現了 HandlerMethodReturnValueHandler 接口,并且該類里面有 returnValueHandlers 屬性是 List 集合屬性,緩存了所有的返回值處理器。不清楚的可以看上面的 2.1 解析器的綁定及匹配

由于返回值處理器也比較多,所以這里也選取一個最常用的 ViewNameMethodReturnValueHandler 返回值解析器看下內部實現原理。首先他肯定實現了 HandlerMethodReturnValueHandler 接口,并實現了該接口里面的兩個方法。

其他相關文章

SpringMVC入門筆記
SpringMVC工作原理之處理映射[HandlerMapping]
SpringMVC工作原理之適配器[HandlerAdapter]
SpringMVC工作原理之參數解析
SpringMVC之自定義參數解析
SpringMVC工作原理之視圖解析及自定義
SpingMVC之<mvc:annotation-driven/>標簽

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容