SpringMVC执行流程源码解析

本文详细探讨了SpringMVC的执行过程,从DispatchServlet开始,分析了doService方法、doDispatch方法以及HandlerMapping和HandlerAdapter的角色。讲解了处理器适配器的选择和执行,包括ModelAndView的创建和视图解析。同时,文章还介绍了SpringMVC的初始化策略,如九大组件的初始化,尤其是HandlerAdapter的初始化。最后,概述了渲染阶段,包括视图解析和模型数据的渲染。整个流程深入浅出,有助于理解SpringMVC的工作机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SpringMVC执行过程

模型图

整体流程
在这里插入图片描述Springmvc细节部分
在这里插入图片描述

现在我们从DispatchServlet开始分析
在这里插入图片描述
在DispatchServlet的父类FrameworkServelt中有doget,dopost,doput,dodelete等方法,这些方法都执行了processRequest方法,这个方法又执行了doService方法,doService在FrameworkServelt中是个虚方法,真正的实现在DispatchServlet中,在这个方法中定义了一些request属性,然后调用doDispatch

这里我们可以看到这个类继承了HttpServlet,
DispatchServlet种的核心方法doDispatch:

核心方法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);

				// Determine handler for the current request.
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				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;
					}
				}

				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler.
				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);
			}
			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);
				}
			}
		}
	}

handle之前的一些前置执行方法

这里我们需要注意在getHandler方法中执行的内容的含义,代码如下,他实际返回的是一条执行链,this.handlerMappings是一个容器 可以把它理解成一个key,value形式的Map集合。

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;
	}

getHandlerAdapater

在getHandler之后 又去请求了getHandlerAdapater,
这里要解释下处理器适配器,首先这个方法返回的是HandlerAdapter类 他是个接口 实现类如下图所示,为什么会有adapter这个方法是因为servelt的配置方式普遍有两种,一种是xml配置方式(SimpleControllerHandlerAdapter处理),一种是注解配置(RequestMappingHandlerAdapter处理)

![在这里插入图片描述](https://img-blog.csdnimg.cn/20210330152907487.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTAyMTUzMTg=,size_16,color_FFFFFF,t_70

springmvc九大组件

protected void initStrategies(ApplicationContext context) {
		//用于上传请求,讲普通请求包装成MultipartHttpServletRequest
		initMultipartResolver(context);
		//从请求中解析Locale 如:中国是zh-CN 用来表示一个区域 实现i18N的基础
		initLocaleResolver(context);
		//用来解析主题
		initThemeResolver(context);
		//处理器映射器  比如标注了@RequestMapping的方法可看成一个handler,handlermapping的作用
		//就是找到这个handle的拦截器和具体处理的handler
		initHandlerMappings(context);
		//处理器适配器 让固定的servlet处理handler
		initHandlerAdapters(context);
		//用于处理handler产生的异常
		initHandlerExceptionResolvers(context);
		//从请求中获取viewname
		initRequestToViewNameTranslator(context);
		//视图解析器,将String类型的视图名,解析成View类
		initViewResolvers(context);
		//重定向时的参数传递
		initFlashMapManager(context);
	}

处理器适配器初始化

如何判断的问题搞清楚了,我们又要思考下一个问题:处理器适配器的初始化时机问题,如下图:在onRefresh方法中调用initStrategies方法,初始化springmvc九大组件

private void initHandlerAdapters(ApplicationContext context) {
		this.handlerAdapters = null;
// 加载所有实现了HandlerAdapter接口的bean detectAllHandlerAdapters 默认为true
		if (this.detectAllHandlerAdapters) {
			// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
			Map<String, HandlerAdapter> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerAdapters = new ArrayList<>(matchingBeans.values());
				// We keep HandlerAdapters in sorted order.
				AnnotationAwareOrderComparator.sort(this.handlerAdapters);
			}
		}
		// 只加载bean name="handlerAdapter"的handlerAdapter
		else {
			try {
				HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
				this.handlerAdapters = Collections.singletonList(ha);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Ignore, we'll add a default HandlerAdapter later.
			}
		}
// 如果仍未找到,从DispatcherServlet.properties加载默认配置
		// Ensure we have at least some HandlerAdapters, by registering
		// default HandlerAdapters if no other adapters are found.
		if (this.handlerAdapters == null) {
			this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
			if (logger.isTraceEnabled()) {
				logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +
						"': using default strategies from DispatcherServlet.properties");
			}
		}
	}

实际处理请求:handle

首先他是HandlerAdapter接口的方法,返回了ModelAndView类,AbstractHandlerMethodAdapter实现了该接口
在这里插入图片描述AbstractHandlerMethodAdapter中的hanle

	@Override
	@Nullable
	public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		return handleInternal(request, response, (HandlerMethod) handler);
	}
//handleInternal
@Override
	protected ModelAndView handleInternal(HttpServletRequest request,
										  HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

		ModelAndView mav;
		checkRequest(request);

		// Execute invokeHandlerMethod in synchronized block if required.
		// 判断当前是否需要支持在同一个session中只能线性地处理请求
		if (this.synchronizeOnSession) {
			// 获取当前请求的session对象
			HttpSession session = request.getSession(false);
			if (session != null) {
				// 为当前session生成一个唯一的可以用于锁定的key
				Object mutex = WebUtils.getSessionMutex(session);
				synchronized (mutex) {
					// 对HandlerMethod进行参数等的适配处理,并调用目标handler
					mav = invokeHandlerMethod(request, response, handlerMethod);
				}
			}
			else {
				// No HttpSession available -> no mutex necessary
				// 如果当前不存在session,则直接对HandlerMethod进行适配
				mav = invokeHandlerMethod(request, response, handlerMethod);
			}
		}
		else {
			// No synchronization on session demanded at all...
			// 如果当前不需要对session进行同步处理,则直接对HandlerMethod进行适配
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}

		if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
			if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
				applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
			}
			else {
				prepareResponse(response);
			}
		}

		return mav;
	}
//************************invokeHandlerMethod
@Nullable
	protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
											   HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		try {
			// 获取容器中全局配置的InitBinder和当前HandlerMethod所对应的Controller中配置的InitBinder,用于进行参数的绑定
			WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
			// 获取容器中全局配置的ModelAttribute和当前当前HandlerMethod所对应的Controller中配置的ModelAttribute,这些配置的方法将会在目标方法调用之前进行调用
			ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

			// 将handlerMethod封装为一个ServletInvocableHandlerMethod对象
			ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
			if (this.argumentResolvers != null) {
				// 设置当前容器中配置的所有ArgumentResolver
				invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
			}
			if (this.returnValueHandlers != null) {
				// 设置当前容器中配置的所有ReturnValueHandler
				invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
			}
			// 将前面创建的WebDataBinderFactory设置到ServletInvocableHandlerMethod中
			invocableMethod.setDataBinderFactory(binderFactory);

			invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

			ModelAndViewContainer mavContainer = new ModelAndViewContainer();
			mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
			// 这里initModel()方法主要作用是调用前面获取到的@ModelAttribute标注的方法,
			// 从而达到@ModelAttribute标注的方法能够在目标Handler调用之前调用的目的
			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);
			}

			// 对请求参数进行处理,调用目标HandlerMethod,并且将返回值封装为一个ModelAndView对象
			invocableMethod.invokeAndHandle(webRequest, mavContainer);
			if (asyncManager.isConcurrentHandlingStarted()) {
				return null;
			}

			// 对封装的ModelAndView进行处理,主要是判断当前请求是否进行了重定向,如果进行了重定向,
			// 还会判断是否需要将FlashAttributes封装到新的请求中
			return getModelAndView(mavContainer, modelFactory, webRequest);
		}
		finally {
			webRequest.requestCompleted();
		}
	}
	//******************invokeAndHandle
	public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

		Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
		setResponseStatus(webRequest);

		if (returnValue == null) {
			if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
				disableContentCachingIfNecessary(webRequest);
				mavContainer.setRequestHandled(true);
				return;
			}
		}
		else if (StringUtils.hasText(getResponseStatusReason())) {
			mavContainer.setRequestHandled(true);
			return;
		}
//***************InvocableHandlerMethod.invokeForRequest
@Nullable
	public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

		Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
		if (logger.isTraceEnabled()) {
			logger.trace("Arguments: " + Arrays.toString(args));
		}
		return doInvoke(args);
	}

源码看到这里,基本的处理流程就已经差不多了,然后是渲染

渲染: processDispatchResult

首先方法的请求参数为request,reponse,mappedhandler(前文提到的处理器执行链),mv(ModelAndView 由handle方法执行返回而成)

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.
		//从request中得到locale  设置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;
		}
	}

///////**********视图解析器中按视图名查找
//this.viewResolvers前文我们已经讲过是在refresh时完成
//初始化的
@Nullable
	protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
			Locale locale, HttpServletRequest request) throws Exception {

		if (this.viewResolvers != null) {
			for (ViewResolver viewResolver : this.viewResolvers) {
				View view = viewResolver.resolveViewName(viewName, locale);
				if (view != null) {
					return view;
				}
			}
		}
		return null;
	}

//////****************AbstractCachingViewResolver.resolveViewName
//判断是否重定向  是否转发,根据不同的情况封装不同的视图
@Override
	@Nullable
	public View resolveViewName(String viewName, Locale locale) throws Exception {
		if (!isCache()) {
			return createView(viewName, locale);
		}
		else {
			Object cacheKey = getCacheKey(viewName, locale);
			View view = this.viewAccessCache.get(cacheKey);
			if (view == null) {
				synchronized (this.viewCreationCache) {
					view = this.viewCreationCache.get(cacheKey);
					if (view == null) {
						// Ask the subclass to create the View object.
						view = createView(viewName, locale);
						if (view == null && this.cacheUnresolved) {
							view = UNRESOLVED_VIEW;
						}
						if (view != null) {
							this.viewAccessCache.put(cacheKey, view);
							this.viewCreationCache.put(cacheKey, view);
						}
					}
				}
			}
			else {
				if (logger.isTraceEnabled()) {
					logger.trace(formatKey(cacheKey) + "served from cache");
				}
			}
			return (view != UNRESOLVED_VIEW ? view : null);
		}
	}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Coffey强

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值