Tomcat 中的 NIO 源码分析
副标题[/!--empirenews.page--]
虽然本文的源码篇幅也不短,但是 Tomcat 的源码毕竟不像 Doug Lea 的并发源码那么“变态”,对于大部分读者来说,阅读难度比之前介绍的其他并发源码要简单一些,所以读者不要觉得有什么压力。 本文基于 Tomcat 当前(2018-03-20)最新版本 9.0.6。 先简单画一张图示意一下本文的主要内容: 目录 源码环境准备 由于上面下载的 tomcat 的源码并没有使用 maven 进行组织,不方便我们看源码,也不方便我们进行调试。这里我们将使用 maven 仓库中的 tomcat-embed-core,自己编写代码进行启动的方式来进行调试。 首先,创建一个空的 maven 工程,然后添加以下依赖。 <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-core</artifactId> <version>9.0.6</version> </dependency> 上面的依赖,只会将 tomcat-embed-core-9.0.6.jar 和 tomcat-annotations-api-9.0.6.jar 两个包引进来,对于本文来说,已经足够了,如果你需要其他功能,需要额外引用其他的依赖,如 Jasper。 然后,使用以下启动方法: public static void main(String[] args) throws LifecycleException {
Tomcat tomcat = new Tomcat;
Connector connector = new Connector("HTTP/1.1"); connector.setPort(8080); tomcat.setConnector(connector);
tomcat.start; tomcat.getServer.await; } 经过以上的代码,我们的 Tomcat 就启动起来了。 Tomcat 中的其他接口感兴趣的读者请自行探索,如设置 webapp 目录,设置 resources 等 这里,介绍第一个重要的概念:Connector。在 Tomcat 中,使用 Connector 来处理连接,一个 Tomcat 可以配置多个 Connector,分别用于监听不同端口,或处理不同协议。 在 Connector 的构造方法中,我们可以传 HTTP/1.1或AJP/1.3用于指定协议,也可以传入相应的协议处理类,毕竟协议不是重点,将不同端口进来的连接对应不同处理类才是正道。典型地,我们可以指定以下几个协议处理类: org.apache.coyote.http11.Http11NioProtocol:对应非阻塞 IO org.apache.coyote.http11.Http11Nio2Protocol:对应异步 IO org.apache.coyote.http2.Htt***rotocol:对应 http2 协议,对 http2 感兴趣的读者,赶紧看起来吧。 本文的重点当然是非阻塞 IO 了,之前已经介绍过异步 IO的基础知识了,读者看完本文后,如果对异步 IO 的处理流程感兴趣,可以自行去分析一遍。 如果你使用 9.0 以前的版本,Tomcat 在启动的时候是会自动配置一个 connector 的,我们可以不用显示配置。 9.0 版本的 Tomcat#start 方法: public void start throws LifecycleException { getServer; server.start; } 8.5 及之前版本的 Tomcat#start 方法: public void start throws LifecycleException { getServer; // 自动配置一个使用非阻塞 IO 的 connector getConnector; server.start; } endpoint 前面我们说过一个 Connector 对应一个协议,当然这描述也不太对,NIO 和 NIO2 就都是处理 HTTP/1.1 的,只不过一个使用非阻塞,一个使用异步。进到指定 protocol 代码,我们就会发现,它们的代码及其简单,只不过是指定了特定的 endpoint。 打开 Http11NioProtocol和Http11Nio2Protocol源码,我们可以看到,在构造方法中,它们分别指定了 NioEndpoint 和 Nio2Endpoint。 // 非阻塞模式 public classHttp11NioProtocolextendsAbstractHttp11JsseProtocol<NioChannel> { publicHttp11NioProtocol { // NioEndpoint super(new NioEndpoint); } ... } // 异步模式 public classHttp11Nio2ProtocolextendsAbstractHttp11JsseProtocol<Nio2Channel> {
publicHttp11Nio2Protocol { // Nio2Endpoint super(new Nio2Endpoint); } ... } 这里介绍第二个重要的概念:endpoint。Tomcat 使用不同的 endpoint 来处理不同的协议请求,今天我们的重点是 NioEndpoint,其使用非阻塞 IO 来进行处理 HTTP/1.1 协议的请求。 (编辑:晋中站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |