目录
一:请求流程
设计了这么多层次的容器,
Tomcat
是怎么确定每一个请求应该由哪个
Wrapper
容器里Servlet来处理的呢?答案是,
Tomcat
是用
Mapper
组件来完成这个任务的。
Mapper
组件的功能就是将用户请求的
URL
定位到一个
Servlet
,它的工作原理是:Mapper组件里保存了
Web
应用的配置信息,其实就是容器组件与访问路径的映射关系,比如Host
容器里配置的域名、
Context
容器里的
Web
应用路径,以及
Wrapper
容器里Servlet映射的路径,你可以想象这些配置信息就是一个多层次的
Map
。
当一个请求到来时,
Mapper
组件通过解析请求
URL
里的域名和路径,再到自己保存的Map里去查找,就能定位到一个
Servlet
。请你注意,一个请求
URL
最后只会定位到一个Wrapper容器,也就是一个
Servlet
。
下面的示意图中 , 就描述了 当用户请求链接
http://www.itcast.cn/bbs/findAll
之后,
是如何找到最终处理业务逻辑的
servlet
。
那上面这幅图只是描述了根据请求的
URL
如何查找到需要执行的
Servlet
, 那么下面我们再来解析一下 , 从Tomcat
的设计架构层面来分析
Tomcat
的请求处理。
步骤如下:
1) Connector
组件
Endpoint
中的
Acceptor
监听客户端套接字连接并接收
Socket
。
2)
将连接交给线程池
Executor
处理,开始执行请求响应任务。
3) Processor
组件读取消息报文,解析请求行、请求体、请求头,封装成
Request
对象。
4) Mapper
组件根据请求行的
URL
值和请求头的
Host
值匹配由哪个
Host
容器、
Context
容器、Wrapper
容器处理请求。
5) CoyoteAdaptor
组件负责将
Connector
组件和
Engine
容器关联起来,把生成的Request对象和响应对象
Response
传递到
Engine
容器中,调用
Pipeline
。
6) Engine
容器的管道开始处理,管道中包含若干个
Valve
、每个
Valve
负责部分处理逻辑。执行完Valve
后会执行基础的
Valve--StandardEngineValve
,负责调用
Host
容器的Pipeline。
7) Host
容器的管道开始处理,流程类似,最后执行
Context
容器的
Pipeline
。
8) Context
容器的管道开始处理,流程类似,最后执行
Wrapper
容器的
Pipeline
。
9) Wrapper
容器的管道开始处理,流程类似,最后执行
Wrapper
容器对应的
Servlet
对象的处理方法。
二:请求流程源码解析
在前面所讲解的
Tomcat
的整体架构中,我们发现
Tomcat
中的各个组件各司其职,组件之间松耦合,确保了整体架构的可伸缩性和可拓展性,那么在组件内部,如何增强组件的灵活性和拓展性呢? 在Tomcat
中,每个
Container
组件采用责任链模式来完成具体的请求处理。
在
Tomcat
中定义了
Pipeline
和
Valve
两个接口,
Pipeline
用于构建责任链, 后者代表责
任链上的每个处理器。
Pipeline
中维护了一个基础的
Valve
,它始终位于
Pipeline
的末端(最后执行),封装了具体的请求处理和输出响应的过程。当然,我们也可以调用 addValve()方法, 为Pipeline
添加其他的
Valve
, 后添加的
Valve
位于基础的
Valve
之前,并按照添加顺序执行。Pipiline
通过获得首个
Valve
来启动整合链条的执行 。