SpringMvc基本组成与源码分析


本次源码分析基于 spring-webmvc-5.2.2.RELEASE.jar

一、SpringMVC请求处理流程

SpringMVC的核心组件和请求处理流程如下:

在这里插入图片描述

  • 1、 DispatcherServletSpringMVC中的前端控制器(front controller),负责接收request并将request转发给对应的处理组件。

  • 2、HanlerMappingSpringMVC中完成urlController映射的组件。DispatcherServlet接收request,然后从HandlerMapping查找处理requestcontroller.

  • 3、Cntroller处理request,并返回ModelAndView对象,ControllerSpringMVC中负责处理request的组件(类似于struts2中的Action),ModelAndView是封装结果视图的组件。

  • 4、视图解析器解析ModelAndView对象并返回对应的视图给客户端。

二、主要组件

2.1、映射处理器

HandlerMapping 是在 Spring 的 3.1 版本之后加入的。它的出现,可以让使用者更加轻松的去配置 SpringMVC 的请求路径映 射。去掉了早期繁琐的 xml 的配置 它的配置有两种方式:都是在 springmvc.xml 中加入配置。

  • 第一种
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappin gHandlerMapping"/>
  • 第二种
 <mvc:annotation‐driven></mvc:annotation‐driven>

2.2、处理器适配器

Spring mvc 采用适配器模式来适配调用指定Handler,根据Handler的不同种类采用不同的 Adapter,其HandlerHandlerAdapter 对应关系如下:

在这里插入图片描述

RequestMappingHandlerAdapter是在实际应用最多的一种,也就是使用@Controller注解形式的

2.3、视图解析器

视图的作用是渲染模型数据,将模型里的数据以某种形式呈现给客户。 为了实现视图模型和具体实现技术的解耦,Springorg.springframework.web.servlet 包中定 义了一个高度抽象的 View 接口。 我们的视图是无状态的,所以他们不会有线程安全的问题。无状态是指对于每一个请求,都会创建 一个 View 对象。

实现接口大概如下:
在这里插入图片描述

适配器会根据不同的处理器选择一个视图解析器,执行不同的操作,比如是重定向到页面,还是返回Json数据响应

三、执行流程源码分析

1、相关配置的初始化

第一步主要是进行一些适配器和映射处理器等的初始化,传统的xml配置下是在DispatcherServletonRefresh方法中。
在这里插入图片描述
SpringBoot下的话是不走这里的,是走WebMvcAutoConfiguration中的Bean,然后在afterPropertySet中去初始化的,比如initHandlerMappings在初始化完后就会有方法跟路径的对应信息了。

在这里插入图片描述

2、请求流程

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、根据请求获取对应的mappedHandler 
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// 2、获取对应的适配器
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				
				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;
					}
				}
				
				// 3、执行拦截器前置
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// 4、由适配器来真正的执行controller方法,返回mv对象
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

				applyDefaultViewName(processedRequest, mv);
				// 5、执行后置拦截器
				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);
			}
			// 6、执行转发结果
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}

	}

上面就是DispatcherServlet中的执行流程,主要的步骤加了注释,接下来分别解释每一点。

1、根据请求获取对应的mappedHandler

在这一步中实际获取到的是HandlerExecutionChain对象来的,也就是就是对handleMethod拦截器这些信息的包装对象来。包括了这个url对应的Bean方法拦截器类型相关的信息。
在这里插入图片描述

2、获取对应的适配器

不同的handler会有不同的适配器来进行真正的流程执行,这一步就是supports判断一下选一个适配器而已。
在这里插入图片描述

3、执行拦截器前置

这一步就是执行拦截器逻辑的前置逻辑而已,如果返回false的在调用一下执行完成的处理逻辑。
在这里插入图片描述

4、由适配器来真正的执行controller方法,返回mv对象

这一步是最重要的一步,包括参数解析、方法执行、mv对象的封装等。

起始位置在RequestMappingHandlerAdapterinvokeHandlerMethod方法中

//  执行
invocableMethod.invokeAndHandle(webRequest, mavContainer);
	if (asyncManager.isConcurrentHandlingStarted()) {
		return null;
	}
// 封装mv对象
return getModelAndView(mavContainer, modelFactory, webRequest);

这一步是先使用参数解析器去解析参数
在这里插入图片描述

然后使用反射执行结果,在封装成mv对象返回

5、执行后置拦截器

这一步跟3是差不多的,一个调用前置,一个调用后置而已

6、执行转发结果

这一步是,如果mv对象不为空的话,就去找对应的试图解析器,然后使用view的解析
在这里插入图片描述

比如HtmlResourceView的解析就是把结果写会response里面去
在这里插入图片描述

最后剩下的就是在前段去渲染视图了。

mvc源码大概就这样了,至于参数的怎么封装和url的解析,这些东西太多了,不一个个去看了。

其中默认的参数解析器构造位置

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值