Spring20 SpringMVC 请求映射

2023年 9月 22日 90.2k 0

Spring-20 SpringMVC 请求映射

Spring 源码系列文章会遵循由浅入深,由易到难,由宏观到微观的原则,目标是尽量降低学习难度,而不是一上来就迷失在源码当中. 文章会从一个场景作为出发点,针对性的目的性极强的针对该场景对 Spring 的实现原理,源码进行探究学习。该系列文章会让你收获什么? 从对 Spring 的使用者成为 Spring 专家。该文章会同步在微信公众号 【DevXJava】, 方便在微信客户端阅读。

本章内容会去详细介绍 Spring MVC 中的 HandlerMapping 组件,也就是核心功能中的将一次 HTTP 请求路由到一个处理器上的过程详解。其实说是详解但是内容并不会很多,不会很细致的去讲解源码,感觉没那个必要(其实是我懒)。会把抽象整理好的,便于理解的内容呈现给读者,给读者一个高度上层视角,而不是陷入到源码的迷宫中。

所谓的处理器映射器请求映射 或者 请求路由 巴拉巴拉一堆名词都是指上图中的 Request Mapping 这个过程 , 完整的表述就是 Http Request Mapping To Java Method. 对应的在 Spring MVC 中实现这个功能的就是 HandlerMapping 所代表的一系列实现类。面向接口编程,体现了框架的可扩展性和代码的稳定性,很优雅。

面向接口编程的两个重要目标就是为了提高扩展性和代码的稳定性(符合开闭原则的代码就是稳定的代码)。比如在 DispatcherServlet 核心代码不做任何的变更情况下,我可以灵活的插拔某个 HandlerMapping 的实现,这样做我就可以改变框架的行为,但是却不用对 DispatcherServlet 的代码做任何一行的更改,这样一来 DispatcherServlet 就是一个经过反复测试稳定的类。而我改变框架行为的动作只会限定在很小的一个范围内,比如我自定义了一个 HandlerMapping 的实现,这样做隔离了变化也就隔离了风险。因为如果我总对某一个类进行修改,那么这个类始终都是不稳定的,毕竟没有人可以承诺他经过修改的代码 100% 没有问题。

HandlerMapping 组件

映射过程的核心方法是 AbstractHandlerMapping#getHandlerInternal 衍生出了一些扩展实现分别提供不同的映射方式,具体的看图这里就不多说了。

	protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;

这个方法的返回值是 Object 这就说明对于处理器类的扩展来说是非常的灵活的,当然也需要其他组件一起协同配合支持。

我们平时用的最频繁的是 RequestMappingInfoHandlerMapping 这个实现就是匹配基于 @RequestMapping 注解的处理器。它的处理映射的核心方法是 RequestMappingInfoHandlerMapping#getMatchingMapping

	@Override
	protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {
		return info.getMatchingCondition(request);
	}

再看下 RequestMappingInfo#getMatchingCondition 这个方法,是不是很简单瞬间就懂了。

	@Override
	@Nullable
	public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
		RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
		if (methods == null) {
			return null;
		}
		ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
		if (params == null) {
			return null;
		}
		HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
		if (headers == null) {
			return null;
		}
		ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
		if (consumes == null) {
			return null;
		}
		ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);
		if (produces == null) {
			return null;
		}
		PathPatternsRequestCondition pathPatterns = null;
		if (this.pathPatternsCondition != null) {
			pathPatterns = this.pathPatternsCondition.getMatchingCondition(request);
			if (pathPatterns == null) {
				return null;
			}
		}
		PatternsRequestCondition patterns = null;
		if (this.patternsCondition != null) {
			patterns = this.patternsCondition.getMatchingCondition(request);
			if (patterns == null) {
				return null;
			}
		}
		RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
		if (custom == null) {
			return null;
		}
		return new RequestMappingInfo(this.name, pathPatterns, patterns,
				methods, params, headers, consumes, produces, custom, this.options);
	}

另外再说一下源码没必要每一行都去看,浪费时间性价比不高,你只需要掌握看源码的能力,还有就是对某个技术或框架有更高视角的了解,大致知道实现原理和部分细节,目的就是为了能把这个技术用的更好,或者更好的解决问题。

匹配到处理器之后会把处理器和拦截器组装成一个调用链对象。

下一个核心步骤就是如何把 HTTP Message 转换成处理器需要的 Java Object 了,这个下一篇内容再讲。

DevX 会持续分享有趣的技术和见闻,如果你觉得本文对你有帮助希望你可以分享给更多的朋友看到。该文章会同步在微信公众号 【DevXJava】, 方便在微信客户端阅读。

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论