天天看点

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-从源码分析它的执行流程

继续阅读