SpringBoot 中DispatcherServlet請求分發流程源碼分析


以一個簡單的請求為例(實際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方法的主要執行流程。

SpringMVC工作原理詳解

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

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM