上一章我们分析了 Tomcat 的核心原理,也清楚了连接器 Connector 的工作流程。今天我们要从源码的角度进一步分析它。本章采用通俗易懂的语言让你能尽快掌握连接器是如何监听端口和处理网络字节流、以及感受一下源码的魅力。
上一章我们分析了 Tomcat 的核心原理,也清楚了连接器 Connector 的工作流程。今天我们要从源码的角度进一步分析它。本章采用通俗易懂的语言让你能尽快掌握连接器是如何监听端口和处理网络字节流、以及感受一下源码的魅力。
监听端口分析
Tomcat 源码分析难度较大。一个人分析还是挺难的。若在已知它的工作原理和流程的情况下。从已知的部分作为突破点,反过来找出未知部分,就变得容易多了。
首先要找突破点。上篇文章分析过,连接器具备监听端口的能力。它是如何监听的端口,会不会和 Socket 监听端口的逻辑一样呢?抱着试一试的心态,我们可以全局代码搜索 bind 和 accept 等关键字。看有没有惊喜出现。
果不其然,在 Endpoint 相关类中出现了Socket 绑定端口和监听请求的代码。我们先打开 NioEndpoint 类一探究竟(NioEndpoint 是默认的通讯端点)。添加几个断点和日志,若 Tomcat 启动后能进入断点,就可以验证我们的猜想是正确的。
NioEndpoint 绑定端口的代码
Endpoint 监听请求的代码
启动服务器验证猜想
处理网络字节流分析
首先要找突破点。上篇文章分析过,连接器接收到的是 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 代码
CoyoteAdapter 将 Request 包装成 HTTPServletRequest 代码
启动服务器验证猜想
连接器小结
通过对源码的跟踪。我们对连接器的理解又加深了很多。
Tomcat 运用了很多反射和模版设计模式的思路。
Tomcat 是通过 Catalina 管理各组件的初始化和启动。采用的是模版设计模式。
连接器的通讯端点是通过 Socket 实现端口的绑定和监听。
连接器的处理器将 Socket 请求数据转换成 coyote 包下的 Request 对象。
容器的 catalina 包下也有一个 Request 对象并实现了Servlet 包下的 HttpServletRequest。
连接器的适配器将 coyote 包下的 Request 对象装成catalina 包下的 Request 对象。采用的是适配器设计模式。
单词知识
以下内容部分来源百度翻译
socket
英 [ˈsɒkɪt] 美 [ˈsɑːkɪt] n.(电源)插座;(电器上的)插口,插孔,管座;托座;孔穴;窝;槽;臼
vt.把…装入插座;给…配插座
Socket 编程在很早以前是一套系列教程。以前面试的时候还经常被问到,甚至要在纸上手写代码。一个无处不在而又容易被忽视的技术。
bind
英 [baɪnd] 美 [baɪnd]
v.捆绑;系;(用长布条)缠绕;(使)联合在一起,结合
n.窘境
accept
英 [əkˈsept] 美 [əkˈsept]
v.收受;接受(建议、邀请等);(认为合适或足够好而)接受;同意;认可
lifecycle
n.生命周期,生活周期
internal
英 [ɪnˈtɜːnl] 美 [ɪnˈtɜːrnl]
adj.内部的;里面的;体内的;(机构)内部的
学英语会编程|ITDragon博客