以一個簡單的請求為例(實際RedisController包含多個請求)
@RestController
@RequestMapping("/redis")
public class RedisController {
@RequestMapping(value = {"/getmsg"})
public String getmsg(){
return "hello";
}
.....
}
整個 DispatcherServlet執行流程:
正常情況下整個request流程代碼都在DispatcherServlet#doService()方法中執行,由同一個線程完成從請求到響應
FrameworkServlet#doPost/doGet
FrameworkServlet#processRequest
DispatcherServlet#doService
DispatcherServlet#doDispatch
doDispatch是SpringMvc中的核心請求處理方法,幾乎全部的請求處理流程都在這個方法中。下圖就是doDispatch方法的主要執行流程。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);//是否上傳文件
multipartRequestParsed = (processedRequest != request);
//根據request信息Uri找到對應HandlerExecutionChain執行鏈
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
//沒有找到HandlerExecutionChain 的通過response反饋
noHandlerFound(processedRequest, response);
return;
}
//通過已找到的Handler取得HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
//緩存
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//pre攔截器執行
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//執行handle,Controller方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
//post攔截器執行(倒序)
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
//頁面跳轉,響應信息
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
DispatcherServlet#getHandler
可以看到springboot啟動時裝載的全部handlerMapping都保存在List<HandlerMapping> handlerMappings中。這里遍歷handlerMappings中所有handlerMapping,直到找到請求對應的Mapping並返回執行立鏈HandlerExecutionChain。因為是@RequestMapping映射,所以遍歷到handlerMappings[1]==RequestMappingHandlerMapping可以找到對應執行鏈。
下邊直接步進到RequestMappingHandlerMapping其繼承自AbstractHandlerMapping。
RequestMappingHandlerMapping初始化時注冊@RequestMapping映射
https://blog.csdn.net/shanchahua123456/article/details/89816167
RequestMappingHandlerMapping成員變量
AbstractHandlerMapping#getHandler
AbstractHandlerMethodMapping#getHandlerInternal
AbstractHandlerMethodMapping其繼承自AbstractHandlerMapping,實現了getHandlerInternal()。
這里取得mappingRegistry的讀鎖,后續就是通過URL從mappingRegistry匹配HandlerMethod(執行方法)。
mappingRegistry中注冊了SpringMvc的控制器和HandlerMethod,以及URL的映射關系。下面有mappingRegistry的成員變量介紹。
AbstractHandlerMethodMapping#lookupHandlerMethod
AbstractHandlerMethodMapping.MappingRegistry#getMappingsByUrl
到這里可以看到通過urlPath從urlLookUp中找到
返回List<RequestMappingInfo>
AbstractHandlerMethodMapping#lookupHandlerMethod
AbstractHandlerMethodMapping#addMatchingMappings
RequestMappingInfoHandlerMapping#getMatchingMapping
AbstractHandlerMethodMapping.MappingRegistry#getMappings
AbstractHandlerMethodMapping#addMatchingMappings
到這里可以看到Spring已經通過mappingRegistry匹配到URL對應HandlerMethod對象,其成員變量包括: Bean對象,Method對象,參數列表等信息。將匹配到的HandlerMethod對象等信息保存到matches中。
mappingRegistry
mappingRegistry對象中成員變量:各種Map還有一個讀寫鎖。
mappingRegistry的各個主要變量
返回 AbstractHandlerMethodMapping#lookupHandlerMethod
返回lookupHandlerMethod()中從返回的List<Match> matches中匹配最合適的handlerMethod返回getHandlerInternal()方法。
if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
if (logger.isTraceEnabled()) {
logger.trace(matches.size() + " matching mappings: " + matches);
}
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
String uri = request.getRequestURI();
throw new IllegalStateException(
"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
返回 AbstractHandlerMethodMapping#getHandlerInternal
此時已取得 handlerMethod。
返回 AbstractHandlerMapping#getHandler
此時已取得 handlerMethod,剩下的工作是完成執行鏈HandlerExecutionChain
取得執行鏈HandlerExecutionChain
AbstractHandlerMapping#getHandlerExecutionChain
創建HandlerExecutionChain(handler),遍歷ArrayList<HandlerInterceptor> adaptedInterceptors把interceptor加入其中。
返回AbstractHandlerMapping#getHandler
返回DispatcherServlet#getHandler
此時已取得完整執行鏈,回到最初的DispatcherServlet類中。
可以看到IDE提示HandlerExecutionChain handler中包含HandlerMethod和兩個攔截器
返回DispatcherServlet#doDispatch
取得執行鏈HandlerExecutionChain 后,取得HandlerAdapter。
HandlerExecutionChain#getHandler
上圖mappedHandler為之前取得的執行鏈HandlerExecutionChain ,取得執行鏈中的handler。
DispatcherServlet#getHandlerAdapter
遍歷handlerAdapters找到合適。
返回DispatcherServlet#doDispatch
此時回到doDispatch方法,已經獲得HandlerExecutionChain和HandlerAdapter。剩下的流程執行前置攔截器,執行Controller,執行post攔截器。
HandlerExecutionChain mappedHandler執行pre攔截器
HandlerExecutionChain#applyPreHandle
執行PRE攔截器,此處將當前執行鏈中的(HandlerMethod)this.handler傳入攔截器。
返回DispatcherServlet#doDispatch
繼續執行Controller方法(Handler)
AbstractHandlerMethodAdapter#handle
RequestMappingHandlerAdapter#handleInternal
RequestMappingHandlerAdapter#invokeHandlerMethod
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
//webRequest : uri=/redis/getmsg;client=127.0.0.1
try {
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
最終會走到此方法中InvocableHandlerMethod#doInvoke
通過HandlerMethod中的BridgedMethod反射執行Controller中的@RequestMapping映射方法調用。
getBridgedMethod().invoke(getBean(), args);
getBridgedMethod()返回的是HandlerMethod中的bridgedMethod(下圖)。
getBean()返回的是HandlerMethod中的bean(下圖)。
RedisController#getmsg
此時通過放射調用,執行真正的RedisController中的@RequestMapping映射方法
一直返回到ServletInvocableHandlerMethod#invokeAndHandle
ModelAndViewContainer mavContainer: View is [null]; default model {} 因為是@RestController,View=null
returnValue="hello"
RequestMappingHandlerAdapter#invokeHandlerMethod
通過getModelAndView()將mavContainer轉換成ModelAndView返回
一直返回DispatcherServlet#doDispatch
Controller@RequestMapping映射方法執行完畢,返回MV。向下執行POST攔截器。
HandlerExecutionChain#applyPostHandle
倒序執行Post攔截器(后進先出)
響應用戶請求DispatcherServlet#processDispatchResult