Tomcat源码分析--资源映射器Mapper

概述

前面说Tomcat是一个容器,其架构图明确表示了各种容器之间的父子关系,这些容器包括engine,host,context和wrapper,并且从上往下构成一个树形结构,即每一个父级容器都可以包括很多个子容器。
此时有一个问题:当客户端发起一个请求(更具体的说是浏览器端的一个URL,比如<http://localhost:8080/ROOT/index.html>)后,Tomcat是怎样知道将要访问的是哪个host,哪个context,哪个wrapper呢?基于这个考虑,Tomcat设计了一种专门用来进行资源映射的组件,即Mapper,其作用就是根据请求去查找这个树形的容器结构,并最终定位到一个具体的Wrapper。

原理分析

映射关系存储模型

为了在诸多容器中实现路径匹配,将web项目最终以servlet级别组织起来,Tomcat维护了一个树形结构。以Mapper组件为根,host作为其子节点,然后context作为host的子节点,wrapper又作为context 的子节点。这样就能将一个请求定位到wrapper级别。其结构图如下:

这里写图片描述

以下是该存储模型的具体实现:

首先提供了一个基本的键值对抽象类,从后面可以看出这个模型的下面几级都实现了这个抽象类

这里写图片描述

回到该模型的最高层,即Mapper,Mapper作为入口,需要保存Host的引用

这里写图片描述

以下是MappedHost类的实现,其保存了ContextList的引用,ContextList从其名称就可看出应该作为Context的列表,保存了很多context。

这里写图片描述
这里写图片描述

MappedContext类对应一个具体的Context,即一个应用,其部分实现如下:

这里写图片描述

一个context可能会对应很多不同的版本,这些版本的具体信息保存在ContextVersion中,其包含了Context下的所有Servlet,包括多种映射方式,如基于精确查找的map,基于通配符的map,基于扩展名的map

这里写图片描述

以下是MappedWrapper的实现

这里写图片描述

至此,就形成了该映射模型的树形结构。

映射过程

Tomcat启动完毕后,这些映射就已经组织好了,接下来就是根据请求去做路由映射了。
请求在经过AbstractHttp11Processor的process方法处理时会调用CoyoteAdaptor的service方法,然后调用其postParseRequest方法,该方法部分实现如下:

这里写图片描述
这里写图片描述

这里会获取Connector所在的service对象,然后调用service内部的Mapper对象的map方法

这里写图片描述

在map方法中调用internalMap方法,传入host,uri,version,并将最终结果保存在request的mappingData里面,internalMap这个方法中包含了路由映射的完整过程,以下是其实现部分:

首先查找请求对应的MappedHost并保存到request对象的mappingData中

这里写图片描述

找到MappedHost后获取该MappedHost下所有的context,并从中找到符合条件的context保存到mappingData中

这里写图片描述
这里写图片描述
这里写图片描述

以上只是获取到了请求对应的context,但是每一个context都可能存在多个版本,接下来要做的工作就是根据指定的version(如果没指定会默认使用最新版本)选择版本对应的对象

这里写图片描述

至此已经知道请求的是哪个host下的哪个context了,但是正如前面所说Tomcat是将一个Web应用以wrapper级别组织起来的,所以找到context之后还需要继续查找具体使用哪个wrapper

这里写图片描述

与host和context的查找不同的是,对host和context的查找时使用的是忽略大小写的二分搜索查找,而对于wrapper的查找涉及到几个不同的步骤。首先尝试使用精确匹配法匹配精确类型的servlet进行匹配,然后尝试使用前缀匹配通配符类型的servlet,然后尝试使用拓展名匹配通配符类型的servlet,最后匹配默认的servlet。这个过程在internalMapWrapper方法中,以下是该方法的实现:

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

因为代码量的问题,这里只分析其中精确查找部分,对于wrapper的精确查找在interMapExactWrapper方法中,方法定义如下:

这里写图片描述

首先调用exactFind()方法找到匹配的wrapper对象,然后将wrapper对象的数据保存到request的mappingData中,exactFind()方法定义如下:

这里写图片描述

查找部分使用的是二分查找,其完整代码如下:

这里写图片描述

至此,根据一个请求就可以定位其请求的host,context以及对其进行处理的wrapper了。

展开阅读全文
©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值