前面分析到 SpringMVC工作原理之處理映射[HandlerMapping] 豹芯,由映射處理器(
HandlerMapping
) 解析出對應(yīng)的handler
意荤。接著 SpringMVC工作原理之適配器[HandlerAdapter] 描述了handler
是怎么匹配到合適的適配器海诲,進(jìn)行handler
對應(yīng)方法的執(zhí)行炮叶。其他幾種適配器還好哥遮,但是RequestMappingHandlerAdapter
適配器對應(yīng)接下來的參數(shù)解析及綁定并執(zhí)行并不是那么簡單笨使,因此本篇筆記主要分析RequestMappingHandlerAdapter
適配器解析對應(yīng)handler
的執(zhí)行流程。
本篇筆記主要分析SpringMVC 5.1.1 這個(gè)版本竞阐。
RequestMappingHandlerAdapter
大概解析流程如下
1 了解在前面
在開始下面的具體源碼分析前缴饭,我們需要了解一些相關(guān)的類和接口
1.1 HandlerMethod
在開始記錄方法執(zhí)行流程前,必須要先說下記錄方法的對象 HandlerMethod
骆莹,HandlerMethod
及子類主要用于封裝方法調(diào)用相關(guān)信息颗搂。簡單理解為保持方法信息的 pojo 類。
分析下各個(gè)類的功能及職責(zé):
-
HandlerMethod
封裝方法定義相關(guān)的信息 (如類幕垦、方法峭火、參數(shù)等) -
InvocableHandlerMethod
參數(shù)準(zhǔn)備委托HandlerMethodArgumentResolver
進(jìn)行具體的解析 -
ServletInvocableHandlerMethod
添加返回值處理職責(zé),ResponseStatus
處理
在容器初始化的時(shí)候智嚷,RequestMappingHandlerMapping
映射處理器就將 @RequestMapping
描述的方法以 RequestMappingInfo
為 key卖丸,HandlerMethod
為 value 放進(jìn)自己的緩存 。至如 HandlerMethod
內(nèi)部后面是怎么進(jìn)行對應(yīng)方法上的參數(shù)解析及綁定到后來的方法執(zhí)行等等盏道,咱們接下來會詳細(xì)講解稍浆。
1.2 參數(shù)解析器(HandlerMethodArgumentResolver
)和返回值的解析器(HandlerMethodReturnValueHandler
)
在分析源碼之前,首先讓我們來看下SpringMVC中兩個(gè)重要的接口猜嘱,兩個(gè)接口都是在 3.1 版本后添加的衅枫。
- 處理方法參數(shù)的解析器接口
- 處理方法調(diào)用返回值的解析器接口
兩個(gè)接口分別有兩個(gè)方法,一個(gè)用來查看該解析器是否支持該參數(shù)的解析朗伶,第二個(gè)方法用來對參數(shù)進(jìn)行解析弦撩。
1.3 默認(rèn)解析器的注入
在容器初始話的時(shí)候,初始化 RequestMappingHandlerAdapter
適配器的時(shí)候會將默認(rèn)的參數(shù)解析器都注入進(jìn)緩存中论皆。
加載默認(rèn)的參數(shù)解析器(ArgumentResolvers)益楼,綁定到 RequestMappingHandlerAdapter
適配器的 argumentResolvers
屬性上。
加載默認(rèn)的返回值解析器(ReturnValueHandlers)点晴,綁定到 RequestMappingHandlerAdapter
適配器的 returnValueHandlers
屬性上感凤。
下面我們來簡單的看下都有哪些默認(rèn)解析器
- 默認(rèn)注入的參數(shù)解析器
- 默認(rèn)注入的返回值解析器
2 解析過程流程
2.1 解析器的綁定及匹配
接著 RequestMappingHandlerAdapter
適配器的 handleInternal(..)
方法往下說,在 handleInternal(..)
方法中主要檢查是否需要同步執(zhí)行接下來對方法的操作粒督,內(nèi)部調(diào)用 invokeHandlerMethod(..)
方法陪竿。
該方法內(nèi)部就方法執(zhí)行流程大致可以分為以上標(biāo)注的 6 步:
①. 對應(yīng) WebDataBinderFactory
工廠類的創(chuàng)建,因里面涉及到的東西有點(diǎn)多屠橄,將放在下面參數(shù)值類型轉(zhuǎn)換部分詳細(xì)解說族跛。
②. 根據(jù)該 HandlerMethod
創(chuàng)建對應(yīng)的 ServletInvocableHandlerMethod
對象。
③. 將注入到緩存的參數(shù)解析器綁定到創(chuàng)建的 ServletInvocableHandlerMethod
對象上锐墙。
④. 將注入緩存的返回值解析器綁定到創(chuàng)建的 ServletInvocableHandlerMethod
對象上礁哄。
⑤. 將上面創(chuàng)建的 WebDataBinderFactory
工廠類對象綁定到創(chuàng)建的 ServletInvocableHandlerMethod
對象上。
⑥. 執(zhí)行 ServletInvocableHandlerMethod
的 invokeAndHandle(...)
方法贮匕。
總結(jié):RequestMappingHandlerAdapter
在內(nèi)部對于每個(gè)請求姐仅,都會實(shí)例化一個(gè) ServletInvocableHandlerMethod
進(jìn)行處理。
ServletInvocableHandlerMethod
內(nèi)部會分別對請求跟響應(yīng)進(jìn)行處理。
進(jìn)入執(zhí)行請求對應(yīng)方法里面看看流程
接下來就是請求參數(shù)解析器和返回值解析器上場的時(shí)候了掏膏。
①. ServletInvocableHandlerMethod
類在處理參數(shù)的時(shí)候劳翰,會使用自己綁定的參數(shù)解析器,參數(shù)解析器記錄在屬性argumentResolvers
(這個(gè)屬性是它的父類 InvocableHandlerMethod
中定義的)馒疹,argumentResolvers
屬性是一個(gè) HandlerMethodArgumentResolverComposite
類(這里使用了組合模式的一種變形)佳簸,這個(gè)類是實(shí)現(xiàn)了 HandlerMethodArgumentResolver
接口的類,實(shí)現(xiàn)了該類里面的兩個(gè)接口颖变。同時(shí)里面有記錄所有參數(shù)解析器的 List
集合生均,有緩存 MethodParameter
與解析器對應(yīng)關(guān)系的 Map
集合。
②. ServletInvocableHandlerMethod
類在處理返回值的時(shí)候腥刹,會使用自身綁定的返回值解析器马胧,該解析器記錄在屬性 returnValueHandlers
(自身屬性),returnValueHandlers
屬性是一個(gè) HandlerMethodReturnValueHandlerComposite
類(這里使用了組合模式的一種變形)衔峰,這個(gè)類實(shí)現(xiàn)了 HandlerMethodReturnValueHandler
接口佩脊,實(shí)現(xiàn)了該接口里面的兩個(gè)方法。同時(shí)里面有記錄所有返回值解析器的 List
集合垫卤。
2.2 參數(shù)解析器內(nèi)部解析流程
因?yàn)榻馕銎魈嗤茫@里只能抽其中一個(gè)來了解下參數(shù)解析器內(nèi)部實(shí)現(xiàn)解析的邏輯,選個(gè)最常用的解析器 RequestParamMethodArgumentResolver
穴肘,他是用來解析 @RequestParam
注解的參數(shù)歇盼。RequestParamMethodArgumentResolver
繼承自 AbstractNamedValueMethodArgumentResolver
,而 AbstractNamedValueMethodArgumentResolver
抽象類實(shí)現(xiàn)了 HandlerMethodArgumentResolver
接口评抚。
首先來看下其支持解析的參數(shù)種類
再來看下其解析參數(shù)的過程
參數(shù)解析的過程可以分為三個(gè)部分:參數(shù)名字解析豹缀、參數(shù)值獲取、參數(shù)值類型轉(zhuǎn)換盈咳。
(1). 參數(shù)名字解析
NamedValueInfo
是該抽象解析器定義的一個(gè)內(nèi)部類耿眉,有三個(gè)屬性記錄形參上的修飾,分別是 name
鱼响、required
、defaultValue
组底,分別記錄形參名字丈积、形參是否必須、形參默認(rèn)值债鸡。
咱們來看下 RequestParamMethodArgumentResolver
子類是怎么實(shí)現(xiàn) createNamedValueInfo(..)
這個(gè)方法的江滨。
很明顯返回的是 RequestParamNamedValueInfo
對象,RequestParamNamedValueInfo
類是該解析類里面的一個(gè)內(nèi)部類厌均,繼承自 NamedValueInfo
唬滑,構(gòu)建方法里面將傳進(jìn)去的 RequestParam
的 name
、required
、defaultValue
分別記錄到創(chuàng)建的 RequestParamNamedValueInfo
對象的屬性上晶密。
通過后面的 updateNameValueInfo(..)
方法檢查一遍擒悬,當(dāng) @RequestParam
注解的 name
和 value
屬性為空時(shí),會自動(dòng)以形參的名字作為 name
稻艰。
(2). 參數(shù)值獲取
resolveName(...)
抽象類的抽象方法懂牧,具體由其子類實(shí)現(xiàn),下面我們來看下 RequestParamMethodArgumentResolver
解析類是怎么實(shí)現(xiàn)的吧尊勿。
上面分別實(shí)現(xiàn)了可變請求和不可變請求對于根據(jù) name
取值的方式僧凤。
(3). 參數(shù)值類型轉(zhuǎn)換
從上面源碼可以看出,通過自身綁定的 binderFactory
創(chuàng)建出 WebDataBinder
對象元扔,通過創(chuàng)建出來的 WebDataBinder
對象來進(jìn)行數(shù)據(jù)轉(zhuǎn)換躯保。
那么接下來的分析就有條理了,分為三個(gè)部分:WebDataBinderFactory
屬性對象的創(chuàng)建及綁定澎语、WebDataBinderFactory
屬性對象內(nèi)部執(zhí)行 createBinder(...)
方法創(chuàng)建出 WebDataBinder
對象的具體邏輯吻氧、 WebDataBinder
進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換的具體邏輯。
(3.1) WebDataBinderFactory
屬性對象的創(chuàng)建及綁定
前面說到在 RequestMappingHandlerAdapter
適配器中執(zhí)行 invokeHandlerMethod(...)
方法咏连,通過 WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
方法創(chuàng)建 WebDataBinderFactory
對象盯孙,并將其綁定在創(chuàng)建的 ServletInvocableHandlerMethod
對象上。
這里的 this.webBindingInitializer
屬性其實(shí)就是一個(gè) ConfigurableWebBindingInitializer
對象祟滴,即在 <mvc:annotation-driven /> 時(shí)默認(rèn)注冊的振惰。即包含一些解析參數(shù)需要的 MessageCodesResolver
、BindingErrorProcessor
垄懂、Validator
骑晶、ConversionService
、PropertyEditorRegistrar[]
草慧。
(3.2) WebDataBinderFactory
對象內(nèi)部執(zhí)行 createBinder(...)
方法創(chuàng)建出 WebDataBinder
對象的具體邏輯
首先來看下 WebDataBinderFactory
接口的實(shí)現(xiàn)類
再來看 createBinder(...)
方法
1 new
出 WebDataBinder
接口實(shí)現(xiàn)類桶蛔,依照自身實(shí)現(xiàn)類為準(zhǔn),從 (3.1) 看出這里的 this
對象是 ServletRequestDataBinderFactory
對象漫谷,new
出來的 WebDataBinder
接口實(shí)現(xiàn)類應(yīng)該是 ExtendedServletRequestDataBinder
類對象仔雷。
2 對 WebDataBinder
對象進(jìn)行一些初始化,this.initializer
屬性是在上面 (3.1) 綁定進(jìn)來的 ConfigurableWebBindingInitializer
對象舔示。
從執(zhí)行方法里面可以看出設(shè)置一些我們在解析參數(shù)時(shí)用到的轉(zhuǎn)換器和驗(yàn)證器到 WebDataBinder
對象上碟婆。
3 自身初始化 WebDataBinder
的方法
從上面 isBinderMethodApplicable(..)
匹配符合該參數(shù)轉(zhuǎn)換的 @initBinder
注解修飾的方法邏輯可以看出,以后在 Controller
里面寫 @initBinder
注解修飾的方法惕稻,盡量指定 value
屬性字段竖共,以免每個(gè)參數(shù)解析都執(zhí)行不必要的 @initBinder
注解修飾的方法。
(3.3) WebDataBinder
進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換的具體邏輯俺祠,執(zhí)行convertIfNecessary(...)
方法
數(shù)據(jù)轉(zhuǎn)換這塊很復(fù)雜公给,我目前的能力只能做潛在的分析借帘。因?yàn)?WebDataBinder
繼承自 DataBinder
,又因?yàn)?DataBinder
實(shí)現(xiàn)了PropertyEditorRegistry
和 TypeConverter
接口淌铐,所以該類具有注入自定義編輯器和轉(zhuǎn)換數(shù)據(jù)的能力肺然。
數(shù)據(jù)的轉(zhuǎn)換最終交給 TypeConverterDelegate
類進(jìn)行轉(zhuǎn)換
從上面可以看出,先匹對自定義的編輯器進(jìn)行數(shù)據(jù)轉(zhuǎn)換匣沼,沒有合適的編輯器則匹配對應(yīng)的轉(zhuǎn)換器進(jìn)行數(shù)據(jù)轉(zhuǎn)換狰挡。
再來看下第 3 步自定義編輯器里面是怎么來轉(zhuǎn)換數(shù)據(jù)的
2.3 返回值析器內(nèi)部解析流程
前面說到返回值處理器記錄在 ServletInvocableHandlerMethod
綁定的 returnValueHandlers
屬性上,returnValueHandlers
屬性是一個(gè) HandlerMethodReturnValueHandlerComposite
類释涛,這個(gè)類是一種組合模式的變形加叁,他也實(shí)現(xiàn)了 HandlerMethodReturnValueHandler
接口,并且該類里面有 returnValueHandlers
屬性是 List
集合屬性唇撬,緩存了所有的返回值處理器它匕。不清楚的可以看上面的 2.1 解析器的綁定及匹配
由于返回值處理器也比較多,所以這里也選取一個(gè)最常用的 ViewNameMethodReturnValueHandler
返回值解析器看下內(nèi)部實(shí)現(xiàn)原理窖认。首先他肯定實(shí)現(xiàn)了 HandlerMethodReturnValueHandler
接口豫柬,并實(shí)現(xiàn)了該接口里面的兩個(gè)方法。
其他相關(guān)文章
SpringMVC入門筆記
SpringMVC工作原理之處理映射[HandlerMapping]
SpringMVC工作原理之適配器[HandlerAdapter]
SpringMVC工作原理之參數(shù)解析
SpringMVC之自定義參數(shù)解析
SpringMVC工作原理之視圖解析及自定義
SpingMVC之<mvc:annotation-driven/>標(biāo)簽