天天看點

springmvc執行流程_SpringMVC-從源碼分析它的執行流程

一、流程圖

springmvc執行流程_SpringMVC-從源碼分析它的執行流程

二、主要流程介紹:

DispatcherServlet

:作為springmvc最重要的一部分,它

本身也是一個Servlet

。它

負責調用HandlerMapping處理我們編寫的handler,傳回HandlerExecutionChain對象,再利用handler比對到合适的HandlerAdapter,使用這個HandlerAdapter對象處理handler,最終傳回一個ModelAndView對象,DispatcherServlet又請求ViewResolver對視圖進行解析,渲染,響應給使用者。
  1. handler(用Object來接收的) :就是我們自己寫的Contorller。我們要使用springmvc來處理,一般有三種方式:第一種是 實作Controller接口 ,第二種可以 實作HttpRequestHandler接口 ,第三種就是 走@RequestMapping注解方式 。這三種方式會分别使用不同的HandlerMapping來處理,傳回的handler類型也不一樣(下面會說),是以handler會使用Object來接收
  2. HandlerExecutionChain :裡面封裝了 handler HandlerInterceptor的List集合
DispatcherServlet繼承了FrameworkServlet(抽象類)

FrameworkServlet又繼承了HttpServlet

并覆寫了HttpServlet的service(HttpServletRequest request, HttpServletResponse response)方法

,FrameworkServlet的service方法也涉及到調用,調用後還做了很多初始化的工作,但這些不重要,重點是它會調用doService方法,FrameworkServlet的doService方法是個抽象方法,是以直接轉到它的實作類DispatcherServlet中去,DispatcherServlet的doService方法又會做很多初始化的工作,向request域儲存很多屬性這些,但重點是他會調用本類的

doDispatch(request, response)方法,這個才是重點。
springmvc執行流程_SpringMVC-從源碼分析它的執行流程

如何調用到doDispatch方法的簡圖

三、源碼分析

DispatcherServlet的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);

				// 1、調用處理器映射器(HandlerMapping),得到HandlerExecutionChain對象
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// 2、根據我們編寫的Contorller得到比對到适合的處理器擴充卡
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				String method = request.getMethod();
				boolean isGet = "GET".equals(method);
				if (isGet || "HEAD".equals(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (logger.isDebugEnabled()) {
						logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
					}
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}
                                // 執行每個攔截器的preHandle方法
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				/*
                                 3、利用處理器擴充卡,執行我們編寫的Contorller方法,
                                并進一步處理,返會ModelAndView對象 */
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}

				applyDefaultViewName(request, mv);
                                // 執行每個攔截器的postHandle方法
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
                        // 對自定義的異常處理器進行捕獲
			catch (Exception ex) {
				dispatchException = ex;
			}
                        // 3、處理結果(頁面渲染),這裡過了,基本主要流程就走完了
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
                        // 異常時執行攔截器的afterCompletion方法
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Error err) {
                        // 錯誤時也會執行攔截器的afterCompletion方法
			triggerAfterCompletionWithError(processedRequest, response, mappedHandler, 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);
				}
			}
		}
	}
           

分析:

核心1(請求 HandlerMapping擷取HandlerExecutionChain對象 ):

mappedHandler =getHandler(processedRequest);
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	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這個List集合(這個集合裡裝了所有的HandlerMapping對象(

BeanNameUrlHandlerMapping

RequestMappingHandlerMapping

)),然後依次執行HandlerMapping(HandlerMapping是所有處理器映射器的頂層接口)的getHandler(request)方法,

  1. BeanNameUrlHandlerMapping: 會處理 xml方式配置的Controller ,這種方式傳回的handler包括 處理器攔截器的集合 自己配置的Controller對象,且用他的頂層接口來接收
  2. RequestMappingHandlerMapping: 會處理 注解方式配置的Contorller ,這種方式傳回的handler包括 處理器攔截器(HandlerInterceptor)的集合 HandlerMethod對象 HandlerMethod裡面又封裝了處理方法的Method對象和我們寫的Contorller對象

核心2(比對到handler的HandlerAdapter):

HandlerAdapter ha =getHandlerAdapter(mappedHandler.getHandler());
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
	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");
}
           

解析:這個方法接收的參數就是封裝在HandlerExecutionChain裡面的handler。首先,它會先周遊HandlerAdapter這個List集合(這個集合裡裝了所有的HandlerAdapter對象(

HttpRequestHandlerAdapter

SimpleControllerHandlerAdapter

RequestMappingHandlerAdapter

)),然後

依次執行HandlerAdapter的supports(handler)方法,來判斷傳入的handler會适配哪一個HandlerAdapter,最終傳回這個比對的HandlerAdapter。
  1. HttpRequestHandlerAdapter: 處理實作了HttpRequestHandler接口的自己寫的控制器
  2. SimpleControllerHandlerAdapter: 處理實作了Conroller接口的自己寫的控制器
  3. RequestMappingHandlerAdapter: 處理使用注解(@RequestMapping)方式的自己寫的控制器

核心3(HandlerAdapter處理handler,傳回ModelAndView對象):

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

解析:調用HandlerAdapter的handle方法,對handler進行處理。這部分源碼很多,而且比較複雜。在這方法裡面主要是

先調用了我們編寫的處理方法并擷取其傳回值

,然後部分源碼如下,它會先周遊returnValueHandler,(這是個存儲傳回值處理器(

HandlerMethodReturnValueHandler

)的List集合,裡面存了13個實作類對象,畢竟傳回值會有很多種情況)

将傳回值與傳回值處理器進行比對,比對成功後用這個HandlerMethodReturnValueHandler的handleReturnValue方法對傳回值進行處理

(就是

将傳回值裝進ModelAndViewContainer這個對象中

ModelAndViewContainer對象裡面裝了一個View和一個ModelMap,View用來裝視圖路徑,ModelMap用來裝資料(這個資料最終會放到request域中去))

,最後再

new一個ModelAndView對象,将ModelAndViewContainer裡的View和ModelMap裝進去,傳回ModelAndView對象
private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) {
	for (HandlerMethodReturnValueHandler returnValueHandler : returnValueHandlers) {
		if (logger.isTraceEnabled()) {
			logger.trace("Testing if return value handler [" + returnValueHandler + "] supports [" +
					returnType.getGenericParameterType() + "]");
		}
		if (returnValueHandler.supportsReturnType(returnType)) {
			return returnValueHandler;
		}
	}
	return null;
}
           
springmvc執行流程_SpringMVC-從源碼分析它的執行流程

核心4(請求ViewResolver對ModelAndView解析,然後頁面渲染):

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
		HttpServletRequest request) throws Exception {
	for (ViewResolver viewResolver : this.viewResolvers) {
		View view = viewResolver.resolveViewName(viewName, locale);
		if (view != null) {
			return view;
		}
	}
	return null;
}
           

這一部分隻是周遊List<ViewResolver>,利用合适的視圖解析器,解析出來View對象。之後會利用這個

View對象的render方法來渲染

,渲染做的就是

取出ModelMap裡面資料放進request域中

,和

對視圖名加上前字尾,利用request擷取到RequestDispatcher對象,然後forward轉發到對應的視圖去。(InternalResourceView裡的部分渲染源碼,看中文解釋就行)
@Override
protected void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

	// 取出model裡的資料儲存到request域中
	exposeModelAsRequestAttributes(model, request);

	// Expose helpers as request attributes, if any.
	exposeHelpers(request);

	// 擷取實體視圖位址(就是轉發路徑)
	String dispatcherPath = prepareForRendering(request, response);

	// (擷取RequestDispatcher以友善後面的轉發)
	RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
	if (rd == null) {
		throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
			"]: Check that the corresponding file exists within your web application archive!");
	}

	// If already included or response already committed, perform include, else forward.
	if (useInclude(request, response)) {
		response.setContentType(getContentType());
		if (logger.isDebugEnabled()) {
			logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
		}
                // 請求轉發
		rd.include(request, response);
}
           
渲染結束,在調用攔截器的afterCompletion方法。到這裡基本節結束了

最後,說一下攔截器的執行順序(都在doDispatch裡調用,然後在HandlerExecutionChain類中執行)

(1)處理器前:
// 調用(DispatcherServlet的doDispatch中)
if (!mappedHandler.applyPreHandle(processedRequest, response)) { //調用
					return;
}
//執行(HandlerExecutionChain類中)
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
	if (getInterceptors() != null) {
		for (int i = 0; i < getInterceptors().length; i++) {
			HandlerInterceptor interceptor = getInterceptors()[i];
			if (!interceptor.preHandle(request, response, this.handler)) {
				triggerAfterCompletion(request, response, null);
				return false;
			}
			this.interceptorIndex = i;
		}
	}
	return true;
}
           

看上面的源碼知道他會在處理前調用,執行

順序也是從0索引開始,傳回true就放行,傳回false就執行攔截器的afterCompletion方法

。最後對interceptorIndex的索引值指派(這個很重要,它會涉及到有很多攔截器時攔截器後兩個方法的分别執行順序,這個索引也是用來保證攔截器的afterCompletion的調用)

(2)處理後渲染前
// 調用(DispatcherServlet的doDispatch中)
mappedHandler.applyPostHandle(processedRequest, response, mv);
//執行(HandlerExecutionChain類中)
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
	if (getInterceptors() == null) {
		return;
	}
	for (int i = getInterceptors().length - 1; i >= 0; i--) {
		HandlerInterceptor interceptor = getInterceptors()[i];
		interceptor.postHandle(request, response, this.handler, mv);
	}
}
           

這一部分執行順序就變了,他會先

從interceptorIndex這個索引開始向前周遊攔截器,然後執行它的postHandle方法 (3) 渲染後
// 調用(DispatcherServlet的doDispatch中)
          // 3、處理結果(頁面渲染),最後會執行攔截器
        processDispatchResult(processedRequest, response, mappedHdler, mv, dispatchException);
        catch (Exception ex) {
               // 異常時執行攔截器的afterCompletion方法
               triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Error err) {
               // 錯誤時也會執行攔截器的afterCompletion方法
               triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
        }
//==================================================================================
//執行(HandlerExecutionChain類中)
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
		throws Exception {
	if (getInterceptors() == null) {
		return;
	}
	for (int i = this.interceptorIndex; i >= 0; i--) {
		HandlerInterceptor interceptor = getInterceptors()[i];
		try {
			interceptor.afterCompletion(request, response, this.handler, ex);
		}
		catch (Throwable ex2) {
			logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
		}
	}
}
           
攔截器的afterCompletion的方法是一定會調用的,捕獲了異常或者錯誤會調用,沒有捕時在渲染結束也會調用。它的執行順序和攔截器的postHandle執行順序一樣 結論:
  1. 某個攔截器的preHandle執行了且傳回為true,那麼它的afterCompletion一定會執行
  2. preHandle方法按順序執行,postHandle和afterCompletion反序調用
  3. 當某一個的攔截器的preHandle方法反回了false,會進入到triggerAfterCompletion(request, response, null); 再根據目前的interceptorIndex索引值,執行前面傳回為true的攔截器的afterCompletion方法

以上就是關于springmvc的執行流程的源碼分析了,因為本人也剛學springmvc,是以了解可能也會存在錯誤,如果有說錯了的地方,希望大家指出來,一起進步。

springmvc執行流程_SpringMVC-從源碼分析它的執行流程

繼續閱讀