vlambda博客
学习文章列表

Tomcat 连接器 Connector 源码追踪




上一章我们分析了 Tomcat 的核心原理,也清楚了连接器 Connector 的工作流程。今天我们要从源码的角度进一步分析它。本章采用通俗易懂的语言让你能尽快掌握连接器是如何监听端口和处理网络字节流、以及感受一下源码的魅力。




Tomcat 连接器 Connector 源码追踪

监听端口分析


Tomcat 源码分析难度较大。一个人分析还是挺难的。若在已知它的工作原理和流程的情况下。从已知的部分作为突破点,反过来找出未知部分,就变得容易多了。


首先要找突破点。上篇文章分析过,连接器具备监听端口的能力。它是如何监听的端口,会不会和 Socket 监听端口的逻辑一样呢?抱着试一试的心态,我们可以全局代码搜索 bind 和 accept 等关键字。看有没有惊喜出现。


果不其然,在 Endpoint 相关类中出现了Socket 绑定端口和监听请求的代码。我们先打开 NioEndpoint 类一探究竟(NioEndpoint 是默认的通讯端点)。添加几个断点和日志,若 Tomcat 启动后能进入断点,就可以验证我们的猜想是正确的。


NioEndpoint 绑定端口的代码

Tomcat 连接器 Connector 源码追踪

Endpoint 监听请求的代码

Tomcat 连接器 Connector 源码追踪

启动服务器验证猜想

Tomcat 连接器 Connector 源码追踪


第一步:服务器启动后 会通过反射初始化 Catalina 容器。
第二步:也是通过反射,调用了 Catalina 的 load 方法。其目的是依次初始化 Tomcat 的 Server、Service、Engine 和 Connector 等组件。
第三步:在连接器Connector 初始化过程中,也开始对内部的 ProtocolHandler 进行初始化。
第四步:随后对 Endpoint 进行初始化,通过 bind 方法进来端口号的绑定。
第五步:在 load 方法执行结束后。也是通过反射,调用了 Catalina 的 start 方法,启动各组件。
第六步:和 load 逻辑一样。start 方法最后一步一步走到 NioEndpoint 的 Acceptor 内部类的run 方法中。开始监听请求。




Tomcat 连接器 Connector 源码追踪

处理网络字节流分析


首先要找突破点。上篇文章分析过,连接器接收到的是 Socket 数据。而真正负责处理业务逻辑的容器 Container 需要的是 HttpServletRequest 对象。这里就需要弄明白连接器是如何将 Socket 转成 Request 并交给容器来处理。那HttpServletRequest 就是我们尝试的突破口。


我们先全局代码搜索 Request 对象,看能否获得更多的可用信息。全局搜索后会惊喜地发现有两个 Request 对象。一个在 coyote 包下(coyote 是连接器框架)。一个在 catalina 包下且实现了 HttpServletRequest 接口。这就是我们想要看到的结果。


思路一下子就很清晰了很多。我们都知道连接器除了有通讯端点 Endpoint 外,还有处理器 Processor 和适配器 Adapter 。处理器负责将 Socket 数据转包装成 coyote.Request 对象。然后交给适配器将 coyote.Request 对象转成 catalina.Request 对象,最后交给容器处理业务逻辑。


Tomcat 的连接器框架是 Coyote,且默认的协议处理器是Http11Protocol ,我们可以先尝试在 Http11Processor 和 CoyoteAdapter 类中找相关代码。(我们可以先加些日志,通过日志打印来缩小和定位代码部分)


Http11Processor 将Socket 包装成 Request 代码

Tomcat 连接器 Connector 源码追踪

CoyoteAdapter 将 Request 包装成 HTTPServletRequest 代码

Tomcat 连接器 Connector 源码追踪

启动服务器验证猜想

Tomcat 连接器 Connector 源码追踪


第一步:Tomcat 服务启动后,NioEndpoint 的 Acceptor 一直处于监听状态。当收到请求后,调用 processSocket 方法,将请求丢到线程池中处理请求,以提高工作效率。
第二步:线程中的 run 方法先对请求进行确认,确认连接正常后交给 Http11Processor 类处理。它通过调用 service 方法将 socket 包装成 request 和response 并交给了适配器。
第三步:适配器通过调用 service 方法将 coyote.Request 包装成容器可以接收的catalina.Request 并调用容器。到这里连接器的任务就结束一般了,等待容器返回结果并反馈给请求。




Tomcat 连接器 Connector 源码追踪

连接器小结


通过对源码的跟踪。我们对连接器的理解又加深了很多。

  • Tomcat 运用了很多反射和模版设计模式的思路。

  • Tomcat 是通过 Catalina 管理各组件的初始化和启动。采用的是模版设计模式。

  • 连接器的通讯端点是通过 Socket 实现端口的绑定和监听。

  • 连接器的处理器将 Socket 请求数据转换成 coyote 包下的 Request 对象。

  • 容器的 catalina 包下也有一个 Request 对象并实现了Servlet 包下的 HttpServletRequest。

  • 连接器的适配器将 coyote 包下的 Request 对象装成catalina 包下的 Request 对象。采用的是适配器设计模式。




Tomcat 连接器 Connector 源码追踪

单词知识


以下内容部分来源百度翻译


socket

socket.mp3 From 学英语会编程 00:01

英 [ˈsɒkɪt]   美 [ˈsɑːkɪt]  n.(电源)插座;(电器上的)插口,插孔,管座;托座;孔穴;窝;槽;臼

vt.把…装入插座;给…配插座


Socket 编程在很早以前是一套系列教程。以前面试的时候还经常被问到,甚至要在纸上手写代码。一个无处不在而又容易被忽视的技术。


bind

bind.mp3 From 学英语会编程 00:01


英 [baɪnd]   美 [baɪnd]  

v.捆绑;系;(用长布条)缠绕;(使)联合在一起,结合

n.窘境


accept

accept.mp3 From 学英语会编程 00:01


英 [əkˈsept]   美 [əkˈsept]  

v.收受;接受(建议、邀请等);(认为合适或足够好而)接受;同意;认可


lifecycle

lifecycle.mp3 From 学英语会编程 00:01


n.生命周期,生活周期


internal

英 [ɪnˈtɜːnl]   美 [ɪnˈtɜːrnl]  

adj.内部的;里面的;体内的;(机构)内部的





Tomcat 连接器 Connector 源码追踪
Tomcat 连接器 Connector 源码追踪



学英语会编程|ITDragon博客

每周一、三、五更新
长按二维码关注