Jetty 相比于 tomcat,更加小巧,更易于定制。

Jetty 的架构

组件化架构

Jetty Server 由若干 Connector、Handler,以及一个线程池组成。
Jetty = HTTP 服务器 + Servlet 容器,Connector 组件和 Handler 组件分别来实现这两个功能。这两个组件工作时所需要的线程资源都直接从一个全局线程池 ThreadPool 中获取。
image.png

Jetty 和 Tomcat 本质都是组件化的架构。
Tomcat 设计了容器来组织这些组件。运用了接口、抽象基类、组合模式。
Jetty 设计了类层次来组织这些组件。运用接口、抽象基类、模板模式。

为了管理这些组件,它们都提供了 Server 作为组件的载体。
为了Jetty 提供了一个 Server 类来启动和协调上面的核心组件。Server 创建并初始化 Connector、Handler、ThreadPool 组件,然后调用 start 方法启动这些组件。

架构区别

一个 Tomcat 实例可以配置多个 Service,不同的 Service 通过不同的连接器监听不同的端口;而 Jetty 中 Connector 是被所有 Handler 共享的。

在 Tomcat 中每个连接器都有自己的线程池,而在 Jetty 中所有的 Connector 共享一个全局的线程池。

Connector

Connector 的组成

跟 Tomcat 一样,Connector 的主要功能是对 I/O 模型和应用层协议的封装。服务端在 I/O 通信上主要完成了三件事情:监听连接、I/O 事件查询以及数据读写。因此 Jetty 设计了 Acceptor、SelectorManager 和 Connection 来分别做这三件事情。

Connector 的 I/O 模型

I/O 模型方面,最新的 Jetty 9 版本只支持 NIO,因此 Jetty 的 Connector 设计有明显的 Java NIO 通信模型的痕迹。
应用层协议方面,跟 Tomcat 的 Processor 一样,Jetty 抽象出了 Connection 组件来封装应用层协议的差异。

Jetty的 I/O 线程模型更像 Netty,Jetty 的 EatWhatYouKill 线程策略,其实就是Netty 4.0中的线程模型。

Jetty 的 Connector 只支持 NIO 模型,跟 Tomcat 的 NioEndpoint 组件一样,它也是通过 Java 的 NIO API 实现的。

Java NIO

Java NIO 有三个关键组件:Channel、Buffer 和 Selector,核心是 Selector。为了方便使用,Jetty 在原生 Selector 组件的基础上做了一些封装,实现了 ManagedSelector 组件。
image.png

Connector 与 NioEndpoint

Connector 包含了应用层协议部分。就线程模型而言,Tomcat 的 NioEndpoint 跟 Jetty 的 Connector 是相似的,都是用一个 Acceptor 数组监听连接,用一个 Selector 数组侦测 I/O 事件,用一个线程池执行请求。

它们的不同点在于,Jetty 使用了一个全局的线程池,所有的线程资源都是从线程池来分配。

Jetty Connector 设计的一大特点是,使用了回调函数来模拟异步 I/O,比如 Connection 向 EndPoint 注册了一堆回调函数。它的本质将函数当作一个参数来传递,告诉对方,你准备好了就调这个回调函数。

Node.js里也是类似的思想,到处都是callback,之后进化到了promise。

补充

IO通信的三阶段

三阶段是接受连接,等待 IO 事件发生,消费数据。
具体的实现???acceptor、selector、connection。

服务端程序的本质

https://time.geekbang.org/column/article/99770

问题

1 多个 acceptor 监听同一个 fd,当 IO 事件到来时,具体通知哪个事件呢?