SpringMVC底層——請求參數處理流程描述
在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
-
-