SpringMVC 请求流程源码剖析

一,SpringMVC

SpringMVC从Spring家族上来讲,他是基于Spring框架的,或者应该说成是Spring框架的表现层框架。因为这点在下载SpringMVC源码的时候,也是要求依赖于Spring框架的搭建基础上引入的Module。如图所示,在搭建SpringMVC源码时候,是基于之前Spring源码剖析时搭建的框架引入的,SpringMVC的执行流程大致的分为了四步:

1,前端控制器DispatchServlet的加载(监听,filter过滤器....),加载指定的配置文件SpringMVC.xml

2,包扫描,扫描指定的注解

3,IOC容器的初始化

4,映射处理器的加载,简历请求URL与Method之间的联系并等待请求

 ★二,前端控制处理器DispatcherServlet的继承结果与源码

继承结构: dispatcherServlet  <-- FrameworkServlet <-- HttpServletBean <--HttpServlet,根据继承结构可以发现dispatcherServlet底层实则还是一个Servlet。

 HttpServlet: doGet & doPost 

底层的基类HttpServlet对于Post,Get请求的处理并没有的做业务上的处理,只是请求协议做了判断判断处理,对于Post,Get请求相比会在上层的子类进行重写。

 FrameworkServlet

为什么会跳过HttpServletBean类,因为这个类中并没有对Post,Get请求的方法进行重写,所以 这里直接省略了。然后可以看到该类中doGet与doPost都会把请求提交给类中的processRequest方法,顾名知义,这个方法应该是处理请求的方法! 然后来到该方法中,可以看到该方法进行了一些请求的前置处理后,会把request,reponse对象继续像doService方法中传递,而在该类中该方法为一个抽象方法,那么必定会在dispatcherServlet中去实现这个方法

 ★DispatcherServlet

dispatcherServlet doService方法前面会对请求的参数,请求头信息做一些处理,处理完成后会继续将请求响应对象向下传递到doDispatch方法中去,以下则为doDispatch处理请求核心代码详细说明。

 ★三,SpringMVC请求大致流程源码细节剖析

上面的部分其实已经把SpringMVC请求流程大致说明了,其核心的方法还是在于doDispatch方法中,主要对其中重要的几个方法进行细节分析

doHandler 

在SpringMVC中Handler也就是我们通常所说的控制层Controller,点进去之后,handlerMapping里面对Spring支持的配置与注解两种注入方式进行遍历去创建HandlerExecutionChain对象,而这个对象中则包含了请求的Url,返回的也就是Handler的执行器对象。

getHandlerAdapter

对于不同的Handler需要构建不同的适配器去执行请求,这里的HandlerAdapters中包含了Spring的三种适配器类型,最终使用返回的适配器类型为 RequestMappingHandlerAdapter

handler

通过前面获取的适配器去handlerMapping,通过反射方式去调用handler中的HandlerMethod并且返回ModelAndView对象,调用方法的过程无非分为两步,参数的解析,方法的获取与调用。进入到该方法中后会去调用invokeHandlerMethod方法。

 invokeHandlerMethod方法很长,这里因为篇幅的问题不做一一的解析,代码中提供了详细的注解,后面着重对invokeAndHandle方法进行跟踪。

	@Nullable
	protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		try {
			//获取容器全局配置的InitBinder和当前HandlerMethod所对应的controller中配置initBinder,用于参数的绑定
			//initBinder: 作用于一些数据类型的转换操作
			WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
			//获取容器全局配置的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标注的方法,保证被标注的方法在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是否需要进行重定向的处理等等
			return getModelAndView(mavContainer, modelFactory, webRequest);
		}
		finally {
			webRequest.requestCompleted();
		}

进入到invokeAndHandle方法中,主要看前面两个方法,一个是获取目标的Handler,对其参数急性解析与方法调用。 首先进入到invoke方法,可以看到执行方式为反射获取方法传入参数执行,这里应证了上面所述反射。

 参数的处理方法getMethodArgumentValues,以下为参数的处理流程,这里没什么好说的,要知道一件事,参数的获取来自Request请求对象。

processDispatchResult 视图渲染的流程

这部分没有什么具体要分析的难点代码,主要搞清楚跳转的流程几个,流程看一下的图

入口: processDispatchResult方法

processDispatchResult -》 render方法

 render-》resolveViewName方法

resolveViewName-》 AbstractCachingViewResolver类中的resolveViewName方法

 resolveViewName.createView -》类中的UrlBasedViewResolver类中的loadView方法。然后到buildView方法中拼接Url,返回view对象

 然后回到DispatcherServlet中的render方法,通过返回的view对象去执行其render方法

 然后到AbstractView中调用render方法设置相应投与渲染视图结束


到这里为止SpringMVC的请求大致流程,四个重要的方法全部剖析完成。

猜你喜欢

转载自blog.csdn.net/qq_42773863/article/details/120463660