SpringMVC系列(一)执行流程

本系列结合源码(基于springboot2.1.4),分析springmvc的执行流程。

先上一个完整的流程图,借用网络上的:
在这里插入图片描述

我们知道,前端发起的请求首先到tomcat,最终执行的是servlet,springmvc实现了一个servlet,叫做DispatcherServlet,其继承关系如下:
在这里插入图片描述
假设发起一个get请求,这时,servlet中的doGet方法会执行,最终执行到DispatcherServlet,链路如下:
FrameworkServlet#doGet(HttpServletRequest request, HttpServletResponse response)
 --》FrameworkServlet#processRequest(HttpServletRequest request, HttpServletResponse response)
  --》DispatcherServlet#doService(HttpServletRequest request, HttpServletResponse response)
    --》DispatcherServlet#doDispatch(HttpServletRequest request, HttpServletResponse response)

最终进入DispatcherServlet类的doDispatch方法中。

doDispatch()方法

这个方法是sprngmvc的核心方法,所有扭转乾坤的逻辑都在这里:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
	HttpServletRequest processedRequest = request;
	//处理器执行链,包含拦截器和具体的controller
	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);

			// Determine handler for the current request.
			//确定要执行的mappedHandler,也就是要执行的controller
			mappedHandler = getHandler(processedRequest);
			if (mappedHandler == null) {
				noHandlerFound(processedRequest, response);
				return;
			}
			// Determine handler adapter for the current request.
			//得到handler适配器,总共有3种
			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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
					return;
				}
			}
			//执行拦截器的preHandle方法
			if (!mappedHandler.applyPreHandle(processedRequest, response)) {
				return;
			}
			// Actually invoke the handler.
			//执行controller,得到model和view
			mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
			if (asyncManager.isConcurrentHandlingStarted()) {
				return;
			}
			//如果没有view名字,设置一个默认的名字
			applyDefaultViewName(processedRequest, mv);
			//执行拦截器的postHandle方法
			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);
		}
		//渲染视图,并将跳转路径设置到response中
		//然后执行拦截器的afterCompletion方法
		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
	}
	catch (Exception ex) {
		//抛异常,也要执行拦截器的afterCompletion方法
		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);
			}
		}
	}
}

主要步骤:
1.确定handlerMapping,并从其中得到HandlerExecutionChain执行链,这个执行链包含了拦截器以及controller方法路径;
2.确定handler适配器,总共有3种:
3.利用适配器执行handler,也就是controller,但是如果有拦截器,那么要先执行拦截器相关方法。
4.渲染视图并返回

关于handlerMapping和适配器在容器中的初始化在《SpringMVC系列(二)HandlerMapping初始化》中分析。
上面是springmvc大致的请求流程,下面针对具体方法详细分析。

getHandler(HttpServletRequest request)

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	if (this.handlerMappings != null) {
		for (HandlerMapping mapping : this.handlerMappings) {
			HandlerExecutionChain handler = mapping.getHandler(request);
			if (handler != null) {
				return handler;
			}
		}
	}
	return null;
}

方法逻辑比较简单,就是遍历
这里handlerMappings是个list,默认有5个实例对象,共4种类型:

  • SimpleUrlHandlerMapping
  • RequestMappingHandlerMapping,处理@Controller修饰的类中,@RequestMapping修饰的方法
  • BeanNameUrlHandlerMapping
  • SimpleUrlHandlerMapping,类型同第一个,但是是不同的实例对象
  • WelcomePageHandlerMapping,默认应用欢迎页面

遍历然后调用mapping.getHandler(request)方法获取HandlerExecutionChain。

其中getHandler方法是在父类AbstractHandlerMapping种实现:

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    //得到handler
	Object handler = getHandlerInternal(request);
	if (handler == null) {
		handler = getDefaultHandler();
	}
	if (handler == null) {
		return null;
	}
	// Bean name or resolved handler?
	if (handler instanceof String) {
		String handlerName = (String) handler;
		handler = obtainApplicationContext().getBean(handlerName);
	}
	//得到执行链,就是添加上拦截器
	HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

	if (logger.isTraceEnabled()) {
		logger.trace("Mapped to " + handler);
	}
	else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
		logger.debug("Mapped to " + executionChain.getHandler());
	}

	if (CorsUtils.isCorsRequest(request)) {
		CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
		CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
		CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
		executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
	}

	return executionChain;
}

第一行代码 getHandlerInternal(request),进入:

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
	String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
	this.mappingRegistry.acquireReadLock();
	try {
		HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
		return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
	}
	finally {
		this.mappingRegistry.releaseReadLock();
	}
}

handlerMethod最终是在mappingRegistry中获取到;
mappingRegistry中维护了多种map,其中就有请求路径和处理方法映射的map,根据请求信息,就可以直接从map中get到。
关于mappingRegistry中的map数据是如何来的,我们在下一篇文章《SpringMVC系列(二)HandlerMapping初始化》中分析。

上面得到handler后,还不是最终要返回的对象,最终返回的是HandlerExecutionChain 类型对象,是个执行链,包含了拦截器,因为要先执行拦截器在执行相关handler方法,

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
	HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
			(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

	String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
	//遍历所有拦截器
	for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
		if (interceptor instanceof MappedInterceptor) {
			MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
			//判断拦截器的配置,当前方法是否被此拦截器拦截
			if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
				chain.addInterceptor(mappedInterceptor.getInterceptor());
			}
		}
		else {
			chain.addInterceptor(interceptor);
		}
	}
	return chain;
}

spring容器在启动的时候,会预先加载所有拦截器,这里进行遍历,判断拦截器的拦截内容,如果符合拦截条件,就将拦截器add到HandlerExecutionChain 对象中形成执行链路。

handlerMapping分析到这,下面HandlerAdapter流程也是类似的。

getHandlerAdapter(Object handler)

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

HandlerAdapter默认有如下3种,初始化流程和HandlerMpping类似,

  • RequestMappingHandlerAdapter
  • HttpRequestHandlerAdapter
  • SimpleControllerHandlerAdapter

上述代码逻辑也是遍历各种Adapter,找到后直接返回。

processDispatchResult()

上面找到HandlerMapping后,得到具体的执行方法,然后使用Adapter执行,最终得到ModelAndView视图,然后使用如下方法进行视图的渲染操作,

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.isTraceEnabled()) {
				logger.trace("No view rendering, null ModelAndView returned.");
			}
		}

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

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

执行渲染动作的是渲染方法render,

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
	// Determine locale for request and apply it to the response.
	Locale locale =
			(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
	response.setLocale(locale);

	View view;
	String viewName = mv.getViewName();
	if (viewName != null) {
		// We need to resolve the view name.
		view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
		if (view == null) {
			throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
					"' in servlet with name '" + getServletName() + "'");
		}
	}
	else {
		// No need to lookup: the ModelAndView object contains the actual View object.
		view = mv.getView();
		if (view == null) {
			throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
					"View object in servlet with name '" + getServletName() + "'");
		}
	}

	// Delegate to the View object for rendering.
	if (logger.isTraceEnabled()) {
		logger.trace("Rendering view [" + view + "] ");
	}
	try {
		if (mv.getStatus() != null) {
			response.setStatus(mv.getStatus().value());
		}
		view.render(mv.getModelInternal(), request, response);
	}
	catch (Exception ex) {
		if (logger.isDebugEnabled()) {
			logger.debug("Error rendering view [" + view + "]", ex);
		}
		throw ex;
	}
}
发布了62 篇原创文章 · 获赞 29 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/csdn_20150804/article/details/103816072