Spring MVC之調(diào)用

前言
在上篇文章我們講解了SpringMVC是如何初始化的,在這篇文章中會(huì)講到其工作流程。
工作流程
大致流程如下:
用戶發(fā)起請(qǐng)求一個(gè)url到中央控制器
中央控制器接收到請(qǐng)求后調(diào)用處理器映射器以獲取相應(yīng)的處理器(即controller)
處理器映射器返回處理器的位置給中央控制器
中央控制器調(diào)用處理器適配器獲取到指定的處理器(即controller)
處理器適配器把請(qǐng)求交給指定的處理器執(zhí)行請(qǐng)求
處理器執(zhí)行完業(yè)務(wù)邏輯后,返回?cái)?shù)據(jù)和視圖給處理器適配器
處理器適配器把數(shù)據(jù)和視圖返回給中央處理器
中央處理器請(qǐng)求視圖解析器進(jìn)行視圖解析
視圖解析器解析相應(yīng)的視圖并返回給中央控制器
中央控制器通過(guò)view將數(shù)據(jù)和模型填充到視圖中
view渲染完視圖后返回給中央控制器
中央控制器把結(jié)果響應(yīng)給用戶

注意:本文是以5.2.3版本為講解。
步驟一:控制請(qǐng)求的轉(zhuǎn)發(fā)
業(yè)務(wù)邏輯如下:
保留請(qǐng)求屬性的快照,以便能夠恢復(fù)原始屬性
給請(qǐng)求體加入一些默認(rèn)屬性,例如:當(dāng)前環(huán)境處理器、主題處理器等
doDispatch:具體處理請(qǐng)求的轉(zhuǎn)發(fā)
并發(fā)處理未開始或可能已完成并且請(qǐng)求進(jìn)一步處理并發(fā)結(jié)果時(shí),恢復(fù)原始快照
在這里doDispatch是我們要關(guān)注的核心方法.

步驟二:具體處理請(qǐng)求的轉(zhuǎn)發(fā)
處理程序?qū)⑼ㄟ^(guò)按順序應(yīng)用servlet的handler映射來(lái)獲得。HandlerAdapter將通過(guò)查詢servlet安裝的HandlerAdapter來(lái)獲得,以找到第一個(gè)支持handler類的HandlerAdapter。所有HTTP方法都由該方法處理。由HandlerAdapter或處理程序自己決定哪些方法是可以接受的。業(yè)務(wù)邏輯如下:
checkMultipart:檢查是否是文件上傳的請(qǐng)求
getHandler:獲取當(dāng)前請(qǐng)求的 HandlerExecutionChain,該鏈上包含處理器及攔截器集合,如果不存在報(bào)404異常
getHandlerAdapter:獲取當(dāng)前請(qǐng)求的處理器適配器
處理以last-modified請(qǐng)求頭的請(qǐng)求
applyPreHandle:應(yīng)用注冊(cè)攔截器的 preHandle 方法
handle:實(shí)際上調(diào)用處理程序
applyDefaultViewName:處理結(jié)果視圖對(duì)象
applyPostHandle:應(yīng)用已注冊(cè)攔截器的 postHandle 方法
processDispatchResult:處理處理器選擇和處理程序調(diào)用的結(jié)果,可以是 ModelAndView,也可以是要解析為 ModelAndView 的 Exception
applyAfterConcurrentHandlingStarted:請(qǐng)求成功響應(yīng)之后的方法


步驟三:獲取當(dāng)前請(qǐng)求的HandlerExecutionChain
循環(huán)遍歷我們初始化<url,controller>哈希表中找到相匹配的執(zhí)行鏈

步驟四:查找請(qǐng)求的處理程序
查找請(qǐng)求的處理程序,如果找不到特定的處理程序,則返回默認(rèn)處理程序。在這里有兩個(gè)核心方法:
getHandlerInternal:查找指定請(qǐng)求的處理程序
getHandlerExecutionChain:為指定的處理程序構(gòu)建一個(gè) HandlerExecutionChain,包括攔截器

步驟五:獲取當(dāng)前請(qǐng)求的處理器適配器
看到這里我們應(yīng)該很熟悉了,在講解aop的時(shí)候我們也用到了supports方法,經(jīng)典的適配器模式。

步驟六:應(yīng)用注冊(cè)攔截器的preHandle方法
業(yè)務(wù)邏輯如下:
通過(guò)getInterceptors方法獲取所有的攔截器
循環(huán)遍歷攔截器觸發(fā)處理器攔截器上的afterCompletion方法回調(diào)

步驟七:實(shí)際上調(diào)用處理程序
實(shí)際調(diào)用的是AbstractHandlerMethodAdapter#handle()方法,該方法具體實(shí)現(xiàn)是在RequestMappingHandlerAdapter類中實(shí)現(xiàn)。

步驟八:使用指定的處理程序方法來(lái)處理請(qǐng)求

步驟九:調(diào)用方法來(lái)處理請(qǐng)求并返回結(jié)果視圖
這個(gè)方法很長(zhǎng),但我們只關(guān)心下面兩個(gè)核心方法:
invokeAndHandler:反射調(diào)用方法處理請(qǐng)求
getModelAndView:返回結(jié)果視圖


步驟十:反射調(diào)用方法處理請(qǐng)求
在這里我們重點(diǎn)關(guān)注下invokeForRequest方法,這個(gè)方法通過(guò)請(qǐng)求的上下文解析參數(shù)值然后反射調(diào)用該方法。

步驟十一:解析參數(shù)及反射調(diào)用方法
業(yè)務(wù)邏輯如下:
getMethodArgumentValues:獲取當(dāng)前請(qǐng)求的方法參數(shù)值,檢查提供的參數(shù)值并回退到配置的參數(shù)解析器,結(jié)果數(shù)組將被傳遞到 doInvoke
doInvoke:使用給定的參數(shù)值調(diào)用處理程序方法

步驟十二:返回結(jié)果視圖

步驟十三:處理結(jié)果視圖對(duì)象


步驟十四:應(yīng)用已注冊(cè)攔截器的postHandle方法
業(yè)務(wù)邏輯如下:
通過(guò)getInterceptors方法獲取所有的攔截器
循環(huán)遍歷攔截器觸發(fā)處理器攔截器上的postHandle方法

步驟十五:處理處理器選擇和處理程序調(diào)用的結(jié)果
核心業(yè)務(wù)邏輯如下:
如果異常非空,處理異常
結(jié)果視圖非空,渲染給定的ModelAndView

步驟十六:按名稱解析視圖
核心業(yè)務(wù)邏輯如下:
resolveViewName:解析視圖名稱
reender:獲取視圖

步驟十七:組裝視圖

時(shí)序圖

寫在最后
好兄弟可以點(diǎn)贊并關(guān)注我的公眾號(hào)“javaAnswer”,全部都是干貨。
