springMVC源碼執行流程

SpringMVC處理請求的流程即爲

  1. 調⽤getHandler()獲取到能夠處理當前請求的執⾏鏈 HandlerExecutionChain(Handler+攔截 器)
  2. 調⽤getHandlerAdapter();獲取能夠執⾏1)中Handler的適配器
  3. 適配器調⽤Handler執⾏ha.handle(總會返回⼀個ModelAndView對象)
  4. 調⽤processDispatchResult()⽅法完成視圖渲染跳轉

doDispathch:

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 {
			// 1 檢查是否是⽂件上傳的請求
			processedRequest = checkMultipart(request);
			multipartRequestParsed = (processedRequest != request);
			// Determine handler for the current request.
			/*
 			 *2 取得處理當前請求的Controller,這⾥也稱爲Handler,即處理器
 			 *這⾥並不是直接返回 Controller,⽽是返回 HandlerExecutionChain 請求處理鏈對象該對象封裝了Handler和Inteceptor
			 */
			mappedHandler = getHandler(processedRequest);
			if (mappedHandler == null) {
				// 如果 handler 爲空,則返回404
				noHandlerFound(processedRequest, response);
				return;
			}
			// Determine handler adapter for the current request.
			// 3 獲取處理請求的處理器適配器 HandlerAdapter
			HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
			// Process last-modified header, if supported by the handler.
			// 處理 last-modified 請求頭
			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;
				}
			}
			if (!mappedHandler.applyPreHandle(processedRequest, response)) {
				return;
			}
			// Actually invoke the handler.
			// 4 實際處理器處理請求,返回結果視圖對象
			mv = ha.handle(processedRequest, response,
					mappedHandler.getHandler());
			if (asyncManager.isConcurrentHandlingStarted()) {
				return;
			}
			// 結果視圖對象的處理
			applyDefaultViewName(processedRequest, mv);
			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);
		}
		// 5 跳轉⻚⾯,渲染視圖
		processDispatchResult(processedRequest, response, mappedHandler, mv,
				dispatchException);
	}
	catch (Exception ex) {
		//最終會調⽤HandlerInterceptor的afterCompletion ⽅法
		triggerAfterCompletion(processedRequest, response, mappedHandler,
				ex);
	}
	catch (Throwable err) {
		//最終會調⽤HandlerInterceptor的afterCompletion ⽅法
		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);
			}
		}
	}
}

getHandler

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
			for (HandlerMapping hm : this.handlerMappings) {
				if (logger.isTraceEnabled()) {
					logger.trace(
							"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
				}
				HandlerExecutionChain handler = hm.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}

遍歷HandlerMapping,試圖獲取能夠處理當前請求的執⾏鏈

getHandlerAdapter

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		if (this.handlerAdapters != null) {
			for (HandlerAdapter ha : this.handlerAdapters) {
				if (logger.isTraceEnabled()) {
					logger.trace("Testing handler adapter [" + ha + "]");
				}
				if (ha.supports(handler)) {
					return ha;
				}
			}
		}
		throw new ServletException("No adapter for handler [" + handler +
				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
	}

ha.handle
在這裏插入圖片描述
processDispatchResult

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
			@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
			@Nullable Exception exception) throws Exception {

		boolean errorView = false;

		if (exception != null) {
			if (exception instanceof ModelAndViewDefiningException) {
				logger.debug("ModelAndViewDefiningException encountered", exception);
				mv = ((ModelAndViewDefiningException) exception).getModelAndView();
			}
			else {
				Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
				mv = processHandlerException(request, response, handler, exception);
				errorView = (mv != null);
			}
		}

		// Did the handler return a view to render?
		if (mv != null && !mv.wasCleared()) {
			//完成渲染
			render(mv, request, response);
			if (errorView) {
				WebUtils.clearErrorRequestAttributes(request);
			}
		}
		else {
			if (logger.isDebugEnabled()) {
				logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
						"': assuming HandlerAdapter completed request handling");
			}
		}

		if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
			// Concurrent handling started during a forward
			return;
		}

		if (mappedHandler != null) {
			mappedHandler.triggerAfterCompletion(request, response, null);
		}
	}

render()完成渲染

在這裏插入圖片描述
視圖解析器解析出View視圖對象

在這裏插入圖片描述
在解析出View視圖對象的過程中會判斷是否重定向、是否轉發等,不同的情況封裝的是不同的
View實現

在這裏插入圖片描述
解析出View視圖對象的過程中,要將邏輯視圖名解析爲物理視圖名

在這裏插入圖片描述
封裝View視圖對象之後,調⽤了view對象的render⽅法

在這裏插入圖片描述
渲染數據

在這裏插入圖片描述
把modelMap中的數據暴露到request域中,這也是爲什麼後臺model.add之後在jsp中可以從請求
域取出來的根本原因

在這裏插入圖片描述
將數據設置到請求域中

發佈了24 篇原創文章 · 獲贊 11 · 訪問量 5528
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章