最近把 Tomcat 主流程源码看了一遍,总结了一点点心得,在这里给大家分享一下。下面我都会引用Tomcat进行举例说明。
为什么要读源码
如果你问我为什么要读 Tomcat 的源码?那么我会告诉你,是因为我感兴趣,我好奇 Tomcat 是如何处理一个网络请求,Tomcat 是如何实现高并发的。抛开兴趣不说,阅读源码对我们日常开发有没有帮助?
肯定是有的,往高的说,如果你阅读的是 Spring 这种优质框架,你可以学习到别人的代码设计理念(我认为这种已经是属于比较高层次的水准了,不仅仅是知道别人在干嘛,而且还知道人家为什么要这么做)。往低的说,拿我遇到的问题举例子。我司的项目突然有一天启动速度突然慢了2倍,我尝试找出当中的原因,trace了一遍启动日志,找出了所有的 GAP(两行日志之间时间间隔大的),但是却无能为力,因为我看不懂源码找不出原因所在。还有一次就是线上 JVM 疯狂 Full GC,我把内存快照dump了下来分析,看到了是哪类对象占用内存最多,虽然这次不能说无能为力(这次靠猜,大概知道是什么原因),但是也不能从根本搞清楚问题所在。
如果你不掌握阅读源码的能力,你永远只能通过二手的信息去了解一门框架,你甚至很多时候都无法判定别人说的是否正确。就算别人说的是正确的,你理解可能也会存在偏差。anyway,实践出真知。
如果看过源码,你有很大的概率能够解决上面所提到的问题。当你熟练掌握阅读一门源码的奇淫技巧之后,你会发现在公司中阅读项目代码的时候也会轻松和清晰很多,总是能很快地找到关键逻辑。
如何阅读源码
下面介绍几个我认为比较重要的几个技巧。
了解框架
这一步是阅读源码最基础的门槛。
想要读懂一门框架的源码的前提是知道这个框架的基本使用(例如:如何创建并部署一个 servlet
,web.xml
、server.xml
这些配置文件的基本使用),知道这个框架的基本架构(例如:Server
、Service
、Engine
、Connector
这几个组件的基本关系)。这部分的知识就需要自己去看官方文档或者一些相关的文章提前了解一下。不能说是直接拿一门完全没有了解过的框架,下载源码咔咔就开始读,这时候你勉强去看大概率会迷失在源码的海洋之中,最终失去动力与方向。
上面说到的基本使用,就是你阅读源码的入手点,你知道如何启动一个Tomcat,你就能通过启动脚本找到启动类,启动方法在哪里。找到启动类之后,你可能就会遇到 server.xml
中的一些核心参数设置与使用。
关注核心逻辑
这一步主要是为了提升阅读效率。
一般来说工业级框架的源码的代码量和复杂度都不低,阅读源码绝对不是要读懂每一行代码,而是读懂我们想要知道的逻辑。所以如何剔除支线代码,成功找到主线代码就显得很为重要(每个人的主线代码不一定是一样的,每个人关注的重点也不一样,也许有人是想了解IO线程模型,有人是想了解如何解析xml配置文件。anyway,你感兴趣的就是主线代码)。
关注核心逻辑?可能有人会问:我代码都没有看,我哪知道什么是核心逻辑?是可以的。什么是核心逻辑?Tomcat 如何处理启动,如何处理一个HTTP请求(随便举两个例子,不是说Tomcat的核心逻辑就只有这两个)。但是这样还不够,这仅仅是你的疑问,如果你想知道Tomcat如何接收并处理一个HTTP请求,你先得用最简单的代码自己实现一个HTTP服务器(其实就是使用BIO、NIO接收socket,解析HTTP报文,向socket写响应),当然这也是有一定的技术门槛的,but你都有阅读源码的想法了,实现一个HTTP服务器也不过分吧(这一切都是为了给自己找思路,如果已经有思路了可以跳过)。写完之后,上面 demo 中的每一行就是你要关注的核心逻辑,这个就是指引你阅读源码的明灯。Tomcat使用NIO实现,你也使用NIO实现,关键的代码应该是差不多的,只不过是Tomcat会比你这个简单demo做多了很多的工作。
ok,你现在已经有思路了就能轻松地在茫茫的代码中快狠准找到关键代码了吗?额,可能还是有点困难,这时候更多的就是靠经验和技巧了。一般从方法变量的命名,代码的注释能知道这段代码大概是干什么。这里我提供其中一个很好用的方法就是逆推,利用你仅有的线索打上一个断点,debug起来,trace 方法栈。如果是找到一个关键的变量,看这个变量是在哪里设置进去的,又使用在了什么地方。
PS:这里多说一句,看源码的过程中,要 记住/理解 每个类对象之间的关系,它们之间是如何协作,这个对宏观理解代码框架很有帮助。
闭环思维
这里的闭环思维指的是将一个流程闭环,例如一个请求进来会 socket.open()
,那么什么时候会调用 socket.close()
呢?当 socket.accept()
的时候 maxConnections
的计数器会累加,那什么时候 maxConnections
的计数器会减掉呢?这个思维会帮助我们完整的理解一个流程,掌握到更多关键信息。闭环的过程中也有可能会发现之前的逻辑漏洞,纠正认知错误。
最后
这里简单介绍了一下阅读源码中的心得,后续会写一些文章具体分析一波源码。