栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringMvc源码全解

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringMvc源码全解

文章目录
  • 1、SpringMVC请求处理流程
  • 2、DispatcherServlet
  • 3、HandlerMapping组件
  • 4、HandlerAdapter组件

1、SpringMVC请求处理流程

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

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

  • 2、HanlerMapping是SpringMVC中完成url到Controller映射的组件。DispatcherServlet接收request,然后从HandlerMapping查找处理request的controller.

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

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

2、DispatcherServlet

前端控制器,也是处理请求开始的地方,先看一下它的结构,然后在逐一分析里面的不同组件。

  • 可以看到它是继承了HttpServlet的,用来接收请求的。
  • 也是实现了ApplicationContextAware接口的可以猜到它是用来获取需要的相关组件的。

我们进去它的父类frameworkServlet会看到Servlet在初始化的时候会给Spring注册一个容器刷新的监听事件,在容器初始化完之后会进来刷新执行初始化操作。

onRefresh则是从容器中获取需要的相关组件,比如MultipartResolver、HandlerMappings、HandlerAdapters等组件。

处理请求的位置则是在org.springframework.web.servlet.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、根据请求找到对应的控制器执行器链HandlerExecutionChain 
			mappedHandler = getHandler(processedRequest);
			if (mappedHandler == null) {
				noHandlerFound(processedRequest, response);
				return;
			}

			// 2、找到对应控制器的适配器,用来执行操作的
			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;
			}

			// 正在执行控制器逻辑
			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) {
			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);
			}
		}
	}
}

DispatcherServlet的大概流程和原理就是这样,但是只看这个基本跟没看没区别,所以我们需要去了解里面的主要的几种组件的原理。

本文只分析了HandlerMapping、HandlerAdapter两种组件。

3、HandlerMapping组件

这里只针对RequestMappingHandlerMapping这个处理器映射器解析,它就是处理@Controller、@RequestMapping等注解的组件了。先看一下它的组成结构,然后再逐一分析它的每一个接口或者抽象类的功能。


可以看到接口功能类型分两类:

  1. 第一部分是Spring容器的扩展支持
  2. 第二部分就是HandlerMapping的功能实现了。

第一部分就是在设置SpringContext的时候执行初始化的功能,从源码可以清楚的看到就是扩展、初始化、判断包装了一下拦截器而已。

重点还是在第二部分,我会根据接口的继承层次一个一个分别讲解。

1、先看HandlerMapping接口,在这个接口中只定义了一个规范,就是接受一个请求返回一个控制器的执行链。

public interface HandlerMapping {
	....略
	
	@Nullable
	HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

在HandlerExecutionChain里面包含了handler、拦截器等主要属性。

其中handler在不同的处理器映射器中存的对象不同,就是具体的执行对象了。在RequestMappingHandlerMapping中存的就是HandlerMethod

拦截器的功能则是在applyPreHandle、applyPostHandle、triggerAfterCompletion、applyAfterConcurrentHandlingStarted这些方法中执行。

2、接着在基础抽象类AbstractHandlerMapping看一下getHandler的处理逻辑。

这一步会有子类去getHandlerInternal获取handler,如果是String的话会当做BeanName去容器中获取具体的对象。

@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	// 获取内部的handler,由子类去实现
	Object handler = getHandlerInternal(request);
	if (handler == null) {
		handler = getDefaultHandler();
	}
	if (handler == null) {
		return null;
	}
	if (handler instanceof String) {
		String handlerName = (String) handler;
		handler = obtainApplicationContext().getBean(handlerName);
	}
	// 拿到handler之后就去获取HandlerExecutionChain
	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());
	}
	// 如果有cors则去获取
	if (hasCorsConfigurationSource(handler)) {
		CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
		CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
		config = (config != null ? config.combine(handlerConfig) : handlerConfig);
		executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
	}
	// 最后返回
	return executionChain;
}

其中getHandlerExecutionChain根据url找出匹配的拦截器放进去,然后再返回。

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
	HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
			(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
	// 获取url
	String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
	// 从已经有的拦截器判断是否MappedInterceptor,如果是则需要匹配路径,不是则默认拦截
	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;
}

至于getHandlerInternal方法由子类实现,先不讲,后面讲到的了继续分析。

3、接着看AbstractHandlerMethodMapping抽象类:

在属性设置完之后会去初始化handlerMethods在processCandidateBean方法中会判断如果类有@Controller、@RequestMapping直接就会去detectHandlerMethods。

protected void detectHandlerMethods(Object handler) {
	// 如果是String当做类型去容器中获取
	Class handlerType = (handler instanceof String ?
			obtainApplicationContext().getType((String) handler) : handler.getClass());

	if (handlerType != null) {
		Class userType = ClassUtils.getUserClass(handlerType);
		// 循环类的每一个方法,获取方法对应Mapping信息
		Map methods = MethodIntrospector.selectMethods(userType,
				(MethodIntrospector.metadataLookup) method -> {
					try {
						return getMappingForMethod(method, userType);
					}
					catch (Throwable ex) {
						throw new IllegalStateException("Invalid mapping on handler class [" +
								userType.getName() + "]: " + method, ex);
					}
				});
		if (logger.isTraceEnabled()) {
			logger.trace(formatMappings(userType, methods));
		}
		// 然后注册进mappingRegistry中
		methods.forEach((method, mapping) -> {
			Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
			registerHandlerMethod(handler, invocableMethod, mapping);
		});
	}
}

在detectHandlerMethods中的逻辑主要就是:

  • 获取每个方法对象MappingInfo信息,其中getMappingForMethod(method, userType)是由子类去实现的。
  • registerHandlerMethod则是将Method 、handler、mapping注册到MappingRegistry中。

    需要注意的是这一步的handler可以是beanName也可以是具体的Bean(也就是Controller)。

4、接着看RequestMappingInfoHandlerMapping,这个抽象类主要是做RequestMappingInfo的匹配判断比较逻辑的。

主要需要了解的是RequestMappingInfo的组成。

如果你看了@RequestMapping注解的话,你就会发现这里就是存了url的匹配条件。

public @interface RequestMapping {

	String name() default "";

	@AliasFor("path")
	String[] value() default {};

	@AliasFor("value")
	String[] path() default {};

	RequestMethod[] method() default {};

	String[] params() default {};

	String[] consumes() default {};

	String[] produces() default {};

}

上面已经扫描的Bean然后解析了MappingInfo信息,还有一个接口就是getHandlerInternal从已经注册的缓存中获取HandlerMethod。

5、最后看RequestMappingHandlerMapping这里比较核心的方法有:

  • isHandler:判断handler类型

  • createRequestMappingInfo:解析注解构建RequestMappingInfo

组成大概就这些,我们直接debug进去看下最后RequestMappingHandlerMapping最终获取的HandlerExecutionChain的组成:

  • 拦截器集合
  • HandlerMethod:包括控制层对象、这个请求匹配的方法、方法参数等信息。


总的来说,RequestMapping就是解析url并注册记录,然后负责根据请求匹配到某个具体的执行对象。

4、HandlerAdapter组件

获取到了对应的handler之后就是执行这个handler了,就交给了HandlerAdapter适配器来执行,并且处理返回结果。

先看一下它的接口定义了哪些规范。

public interface HandlerAdapter {
	// 判断支持的handler
	boolean supports(Object handler);
	// 执行handler并且返回结果。
	@Nullable
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
	// 根据handler决定是否需要修改request
	long getLastModified(HttpServletRequest request, Object handler);

}

第一个的话就是判断支持对象了:

具体的执行方法:

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

		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		try {
			WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
			ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

			ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
			if (this.argumentResolvers != null) {
				invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
			}
			if (this.returnValueHandlers != null) {
				invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
			}
			invocableMethod.setDataBinderFactory(binderFactory);
			invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

			ModelAndViewContainer mavContainer = new ModelAndViewContainer();
			mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
			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);
			}

			invocableMethod.invokeAndHandle(webRequest, mavContainer);
			if (asyncManager.isConcurrentHandlingStarted()) {
				return null;
			}

			return getModelAndView(mavContainer, modelFactory, webRequest);
		}
		finally {
			webRequest.requestCompleted();
		}
	}

就是解析参数,执行具体对象的方法,然后根据返回类型返回详情数据。其他的看累了,先不写了。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/583372.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号