一个 Servlet 主要做下面三件事情:
创建并填充 Request 对象, 包括: URI, 参数, method, 请求头信息, 请求体信息等
创建 Response 对象
执行业务逻辑, 将结果通过 Response 的输出流输出到客户端
Servlet 没有 main 方法, 所以, 如果要执行, 则需要在一个容器里面才能执行, 这个容器就是为了支持 Servlet 的功能而存在, Tomcat 其实就是一个 Servlet 容器的实现.
整体架构图
从上图我们看出, 最核心的两个组件 -- 连接器 (Connector) 和容器 (Container) 起到心脏的作用, 他们至关重要! 他们的作用如下:
1,Connector 用于处理连接相关的事情, 并提供 Socket 与 Request 和 Response 相关的转化;
2,Container 用于封装和管理 Servlet, 以及具体处理 Request 请求;
一个 Tomcat 中只有一个 Server, 一个 Server 可以包含多个 Service, 一个 Service 只有一个 Container, 但是可以有多个 Connectors, 这是因为一个服务可以有多个连接, 如同时提供 Http 和 Https 链接, 也可以提供向相同协议不同端口的连接, 示意图如下(Engine,Host,Context 下边会说到):
多个 Connector 和一个 Container 就形成了一个 Service, 有了 Service 就可以对外提供服务了, 但是 Service 还要一个生存的环境, 必须要有人能够给她生命, 掌握其生死大权, 那就非 Server 莫属了! 所以整个 Tomcat 的生命周期由 Server 控制.
另外, 上述的包含关系或者说是父子关系, 都可以在 tomcat 的 conf 目录下的 server.xml 配置文件中看出
上边的配置文件, 还可以通过下边的一张结构图更清楚的理解:
下面我们逐一来分析各个组件的功能:
Server 表示服务器, 提供了一种优雅的方式来启动和停止整个系统, 不必单独启停连接器和容器
Service 表示服务, Server 可以运行多个服务. 比如一个 Tomcat 里面可运行订单服务, 支付服务, 用户服务等等
每个 Service 可包含多个 Connector 和一个 Container. 因为每个服务允许同时支持多种协议, 但是每种协议最终执行的 Servlet 却是相同的
Connector 表示连接器, 比如一个服务可以同时支持 AJP 协议, Http 协议和 Https 协议, 每种协议可使用一种连接器来支持
Container 表示容器, 可以看做 Servlet 容器
Engine -- 引擎
Host -- 主机
Context -- 上下文
Wrapper -- 包装器
Service 服务之下还有各种支撑组件, 下面简单罗列一下这些组件
Manager -- 管理器, 用于管理会话 Session
Logger -- 日志器, 用于管理日志
Loader -- 加载器, 和类加载有关, 只会开放给 Context 所使用
Pipeline -- 管道组件, 配合 Valve 实现过滤器功能
Valve -- 阀门组件, 配合 Pipeline 实现过滤器功能
Realm -- 认证授权组件
除了连接器和容器, 管道组件和阀门组件也很关键, 我们通过一张图来看看这两个组件
Connector 和 Container 的微妙关系
由上述内容我们大致可以知道一个请求发送到 Tomcat 之后, 首先经过 Service 然后会交给我们的 Connector,Connector 用于接收请求并将接收的请求封装为 Request 和 Response 来具体处理, Request 和 Response 封装完之后再交由 Container 进行处理, Container 处理完请求之后再返回给 Connector, 最后在由 Connector 通过 Socket 将处理的结果返回给客户端, 这样整个请求的就处理完了!
Connector 最底层使用的是 Socket 来进行连接的, Request 和 Response 是按照 HTTP 协议来封装的, 所以 Connector 同时需要实现 TCP/IP 协议和 HTTP 协议!
Connector 架构分析
Connector 用于接受请求并将请求封装成 Request 和 Response, 然后交给 Container 进行处理, Container 处理完之后在交给 Connector 返回给客户端.
因此, 我们可以把 Connector 分为四个方面进行理解:
(1)Connector 如何接受请求的?
(2)如何将请求封装成 Request 和 Response 的?
(3)封装完之后的 Request 和 Response 如何交给 Container 进行处理的?
首先看一下 Connector 的结构图, 如下所示:
Connector 就是使用 ProtocolHandler 来处理请求的, 不同的 ProtocolHandler 代表不同的连接类型, 比如: Http11Protocol 使用的是普通 Socket 来连接的, Http11NioProtocol 使用的是 NioSocket 来连接的.
其中 ProtocolHandler 由包含了三个部件: Endpoint,Processor,Adapter.
(1)Endpoint 用来处理底层 Socket 的网络连接, Processor 用于将 Endpoint 接收到的 Socket 封装成 Request,Adapter 用于将 Request 交给 Container 进行具体的处理.
(2)Endpoint 由于是处理底层的 Socket 网络连接, 因此 Endpoint 是用来实现 TCP/IP 协议的, 而 Processor 用来实现 HTTP 协议的, Adapter 将请求适配到 Servlet 容器进行具体的处理.
(3)Endpoint 的抽象实现 AbstractEndpoint 里面定义的 Acceptor 和 AsyncTimeout 两个内部类和一个 Handler 接口. Acceptor 用于监听请求, AsyncTimeout 用于检查异步 Request 的超时, Handler 用于处理接收到的 Socket, 在内部调用 Processor 进行处理.
Container 如何处理请求的
Container 处理请求是使用 Pipeline-Valve 管道来处理的!(Valve 是阀门之意)
Pipeline-Valve 是责任链模式, 责任链模式是指在一个请求处理的过程中有很多处理者依次对请求进行处理, 每个处理者负责做自己相应的处理, 处理完之后将处理后的请求返回, 再让下一个处理着继续处理.
但是! Pipeline-Valve 使用的责任链模式和普通的责任链模式有些不同! 区别主要有以下两点:
(1)每个 Pipeline 都有特定的 Valve, 而且是在管道的最后一个执行, 这个 Valve 叫做 BaseValve,BaseValve 是不可删除的;
(2)在上层容器的管道的 BaseValve 中会调用下层容器的管道.
我们知道 Container 包含四个子容器, 而这四个子容器对应的 BaseValve 分别在: StandardEngineValve,StandardHostValve,StandardContextValve,StandardWrapperValve.
Pipeline 的处理流程图如下:
(1)Connector 在接收到请求后会首先调用最顶层容器的 Pipeline 来处理, 这里的最顶层容器的 Pipeline 就是 EnginePipeline(Engine 的管道);
(2)在 Engine 的管道中依次会执行 EngineValve1,EngineValve2 等等, 最后会执行 StandardEngineValve, 在 StandardEngineValve 中会调用 Host 管道, 然后再依次执行 Host 的 HostValve1,HostValve2 等, 最后在执行 StandardHostValve, 然后再依次调用 Context 的管道和 Wrapper 的管道, 最后执行到 StandardWrapperValve.
(3)当执行到 StandardWrapperValve 的时候, 会在 StandardWrapperValve 中创建 FilterChain, 并调用其 doFilter 方法来处理请求, 这个 FilterChain 包含着我们配置的与请求相匹配的 Filter 和 Servlet, 其 doFilter 方法会依次调用所有的 Filter 的 doFilter 方法和 Servlet 的 service 方法, 这样请求就得到了处理!
(4)当所有的 Pipeline-Valve 都执行完之后, 并且处理完了具体的请求, 这个时候就可以将返回的结果交给 Connector 了, Connector 在通过 Socket 的方式将结果返回给客户端.
总结
好了, 我们已经从整体上看到了 Tomcat 的结构, 但是对于每个组件我们并没有详细分析. 后续章节我们会从几个方面来学习 Tomcat:
逐一分析各个组件
通过断点的方式来跟踪 Tomcat 代码中的一次完整请求
来源: https://www.cnblogs.com/java-chen-hao/p/11316795.html