在DispatcherServlet.java的doDispatch方法中,springmvc通過handlermapping裡面找哪個handler能處理請求,handler封裝了目標方法的資訊,
mappedHandler = getHandler(processedRequest);
然後為當前的handler找到一個介面卡HandlerAdapter,尋找的過程為:在DispatcherServlet.java的getHandlerAdapter方法中,挨個匹配,判斷當前adapter是否支援當前handler,判斷方法為只要handler是handlerMethod型別就生效,就支援
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
找到介面卡以後判斷當前請求是不是“GET”方法以及“HEAD”,“HEAD”不是伺服器真正處理的
介面卡HandlerAdapter把(目標方法、request、response)傳入handle執行目標方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
怎麼執行目標方法:
- 先得到handler
return this.handler;
- 再進入內部處理細節RequestMappingHandlerAdapter.java,呼叫的invokeHandlerMethod就是執行目標方法
mav = invokeHandlerMethod(request,response,handlerMethod);
-
在RequestMappingHandlerAdapter.java的invokeHandlerMethod方法中,
-
為invocableMethod方法設定引數解析器argumentResolvers,引數解析器確定將要執行的目標方法的每一個引數的值是什麼
-
當前解析器是否支援解析這種引數
-
支援就呼叫 resolveArgument
-
-
為invocableMethod方法設定返回值處理器returnValueHandlers
-
-
把26個argumentResolvers和15個returnValueHandlers都放入目標方法包裝的ServletInvocableHandlerMethod中
-
然後真正執行目標方法的語句
invocableMethod.invokeAndHandle(WebRequest,mavContainer);
-
在ServletInvocableHandlerMethod.java的invokeAndHandle方法中,執行了controller
Object returnValue = invokeForRequest(webRequest,mavContainer,proviedArgs);
-
step into 進入InvocableHandlerMethod.java,確定目標方法每一個引數的值
Object[] agrs = getMethodArgumentValues(request,mavContainer,providerArgs)
-
在InvocableHandlerMethod.java的getMethodArgumentValues方法中,先獲取方法所有的引數宣告(詳細資訊)。
MethodParameter[] parameters = getMethodParameters();
-
判斷引數是否為空,為空則無需確定任何值直接返回;
if (ObjectUtils.isEmpty(parameters)) { return EMPTY_ARGS; }
如果有引數列表,new一個Object[],引數列表有多少個Object[]就有多長
Object[] args = new Object[parameters.length]; for (int i = 0; i < parameters.length; i++) { MethodParameter parameter = parameters[i]; parameter.initParameterNameDiscovery(this.parameterNameDiscoverer); args[i] = findProvidedArgument(parameter, providedArgs);
先宣告args遍歷parameters,給args[i]賦值,args[i]的值解析器解析了才有
-
解析之前,判斷26個解析器是不是supportsParamter支援這個引數型別。
this.resolvers.supportsParameter(parameter)
-
HandlerMethodArgumentResolverComposite.java的getArgumentResolver方法中
-
獲取一個快取result
-
result==null,進入增強for迴圈,逐個確定26個解析器誰能支援這種引數
- supportsParameter方法,傳來的引數有沒有hasParameterAnnotation標註註解
- 沒有就return false
- 如果標了,再判斷引數是否map型別,
- return true支援解析
-
當前resolver支援解析,放到快取裡邊,判斷成功,進入解析
-
-
解析引數
this.resolvers.resolveArgument
- HandlerMethodArgumentResolverComposite.java的resolverArgument方法中,先拿到所有的引數解析器getArgumentResolver
- 呼叫引數解析器的resolverArgument方法進行解析
- 獲取引數名字資訊
- 解析引數的名字,placeholderResolved、BeanExpressionResolver解析evaluate計算名字,按照正則匹配的方式
- 解析引數的值
- uriTemlateVars 在request請求域中拿到值;UrlPathHelper會把uri地址裡邊的所有的路徑變數全部解析出來並儲存到請求域中
-
遍歷迴圈所有引數
-
-
最終返回args,args就是確定好的值
-
-
處理返回結果的時候,把mavContainer傳進去,
this.returnValueHandlers.handlerReturnValue
-
在handlerMethod.java的getReturnValueType方法中獲取返回的結果型別
-
HandlerMethodArgumentResolverComposite.java的handleReturnValue方法中,
找到返回值的處理器
如果返回值是一個字串,拿到字串然後儲存到mavContainer
-
-
返回值處理完以後,getModelAndView
-
-
目標方法執行完成
將所有的資料都放在 ModelAndViewContainer;包含要去的頁面地址View。還包含Model資料。
-
從ModelAndViewContainer拿到預設的Model,updateBindingResult,拿到key放到繫結裡邊,又被封裝成ModelAndView,然後返回這個新封裝的mav
-
處理派發結果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
拿到所有請求域中的屬性,解析得到檢視名
渲染頁面
view.render(mv.getModelInternal(),request,response);
拿到頁面資料
createMergeOutputModel(model,request,response); 創造合併的輸出模型
如果model不等於空
mergeModel.putAll(model)//即把資料轉移到HashMap
渲染合併輸出的模型資料
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
-
把上面的Hashmap傳進來了
-
拿到請求物件,獲取的原生的Servletrequest
return originalRequest
-
暴露模型作為請求域屬性
// Expose the model object as request attributes. exposeModelAsRequestAttributes(model, request);
- 把model裡面的東西進行遍歷
- 遍歷以後每一個request setAttribute
-
-