我的源码阅读经历
❝这篇文章主要总结我从毕业到现在的源码阅读经历,希望能够助你探索一条适合自己的源码之路。
❞
1 为什么要读源码
关于阅读源码的收益网上有很多分享,以下是我的观点:
「快速参与项目」。做为一线开发者,到一家新公司,进入新项目,免不了要去深入了解项目,而学会高效阅读和调试代码,能够迅速熟悉新项目,更短时间内参与到新项目的开发,从而省出更多的时间来给自己充电。作为搞技术的同学,一定要终身学习,而你每天的学习时间就是在一点一滴中积累起来的。
「打磨编程技艺」。通过阅读开源框架的源码,可以有效地提升编程技能,学到优秀的设计模式,形成自己的编程风格。对于一些经典框架的设计,比如 Spring,Mybatis,如果你没深入读过源码,很难去了解其设计的精髓,面试官随便深入几个问题立马露馅。
「解决疑难杂症」。掌握高效阅读和调试源码的思路和技巧,你可以更快地定位和解决疑难杂症,跨语言去阅读其他领域的开源框架,达到技能和语言无关的境界,感谢 JetBrains 给我们提供的 IntelliJ 系列的工具,大幅减少跨语言的迁移成本。
阅读一款优秀的开源框架源码,就像阅读一部引人入胜的侦探小说,在这个过程中,你会逐渐解开一个个谜题,环环相扣,最终水落石出。这篇文章,我会分享我从毕业到现在的阅读源码经历,下篇文章,我会分享一些阅读源码的关键思路和调试技巧。
2 我的源码阅读经历
回顾 2014 年毕业到现在,我的源码阅读经历大致可分为三个时期:探索期,成长期,成熟期。
2.1 探索期:2014年 ~ 2016年
探索期大概是 2014年 ~ 2016年,两年左右的时间,这段时期结束的标志是快捷键的精通和 Tomcat 底层原理的掌握。
探索期前部分时间花在了 IDEA 快捷键的练习。刚毕业的半年时间里,每天都会花大量的时间去练快捷键,刚开始真的是死记硬背。
当时的具体做法是:
把每个快捷键都写在便利贴上并注明 Deadline,每一行格式大概是 "抽取方法参数 ALT+CMD+P 12.31" ,每个便利贴写五行,便利贴贴在工位,抬头就能看到。 每天上班前把每个便利贴都操作几遍,一段时间之后,当便利贴上的五个快捷键都烂熟于心的时候,就撕下便利贴,贴在一本记事本上,前期每天新抄一张便利贴,也就是五个快捷键。 最多的时候,便利贴应该有七八张,也就是几十个快捷键,此后,每撕下一张便利贴,就抄一些新的,开始进入循环。 随着记事本上的便利贴越来越多,也需要隔几天来复习一遍,偶尔碰到几个平时不怎么用的,若回忆不起来,就重新抄一遍在新的便利贴上贴在工位。 在编码或调试过程中,如果某些快捷键之前已经记忆过,就强制自己必须要用快捷键完成,如果回忆有卡顿,哪怕只有一秒,也要重新抄在新便利贴上,进入下一轮循环。
经过这段时间的刻意练习,结果是我现在能够记住接近 200 多个快捷键组合,且是肌肉记忆。
打下良好的基础之后,我开始尝试阅读 Tomcat 的源码,说实话,第一次干起来非常费劲,经常陷入到细节中不能自拔,没有捷径,这段时间必须得你自己度过。这段过程也有惊喜,就是第一次知道如何通过 Socket 实现一个 Http 服务器,那种感觉非常畅快,一下子激发了我探索源码世界的好奇心。
总的来说,这段时间只能是对着一本 Tomcat 源码的书来阅读源码,看到哪算哪,还没有形成自己阅读源码的思路,但是经过这段经历,我了解到,其实了解开源框架源码没这么难,只要肯花功夫,哪怕沿着别人的思路去探索,也能了解底层原理。
这段时间做的比较有意义的输出是,我把快捷键的经验录成了视频,帮助了 10w+ 的开发者:
如果你也处在第一个阶段,我的一个建议是,花点时间好好背背快捷键吧。
2.2 成长期:16年 ~ 19年
成长期大概是 16年 ~ 19年,三年左右的时间,这段时间结束的标志是 Netty 源码分析视频课程的上线。
大概毕业一两年之后吧,我开始阅读 Spring 的源码,第一次读就被 Spring 优美的设计和代码风格给吸引到,直到现在,我还是认为 Spring 是开源世界中最美的代码。
当时读 Spring 源码也是参考了一本源码指导的书(所以大家没事一定要多读读书呀)。和探索期不一样的是,在这个时期,调试技能有一定的提升,尤其是一些场景下的组合调试技能,逐渐开始形成自己的方法论。接下来开始做源码分析的分享,记得有一次分享 Spring 的核心流程,连续讲了两三个小时都不带停顿的。
由于对 Spring 源码的熟悉,当时组内同学还给起了个奇怪的外号,叫做 "Spring fairy",翻译成中文是 "春仙",这个组内昵称保留到了现在,"闪电侠" 也干不过。
成长期的中间那段时间,接到一个长连相关的项目(感谢勇哥的信任),核心技术用到了 Netty,当时了解到这个框架是几乎所有中间件最底层的技术,于是在完成项目目标的同时,开始研究 Netty 底层的实现。
和 Tomcat、Spring 不一样的是,那个时候 Netty 相关的原理分析相关的文章几乎为零,只能自己尝试去啃。
有了前面几年的基础,自己阅读源码的关键思路和调试技巧逐渐稳定,尝试在不参考任何原理分析资料的情况下自己去探索,确实花了非常多的时间,在这个过程中有煎熬,有兴奋,有停滞不前,也有豁然开朗,但是,终究这只硬骨头还是被我啃下了。
啃的过程对于别人来说可能相对枯燥,但是对我来说其乐无穷:几乎每天下班,每个周末都会打开源码,一调试就是几个小时,不断地 "CMD F2,Shift F9,F7...",调试技能因此得到了打磨,积累了很多调试技巧。
同时,那段时间,周末花了大量的时间去写 Netty 底层原理的相关的文章,通过文章结识了不少同行,部分甚至成为现在的同事。
后来慕课的编辑通过我的文章找到我,想合作出一门课,再三考虑之下,我决定出一门 Netty 源码分析相关的视频课程来拓荒,更好地帮助在这条路上探索的同行。视频课程要比写文章要难,因为出错的成本比较高,无法反复修改。
当时没有办法,只能硬着头皮,再次深入到 Netty 的底层世界中,不断地啃,反复地啃,每次录制一个新的章节之前,都会再花大量的时间去啃细节,抓脉络,直到这个章节涉及到所有的部分烂熟于心才开始录制。
最终,《Java 读源码之 Netty 深入剖析》这门视频课程在 18 年中在慕课上线,前后大概花了大半年的时间,每个周末要么在录视频,要么在录视频的路上。
总结这段时期的转变:通过阅读 Spring 和 Netty 源码,及文章博客、视频课的分享,基本形成了阅读源码的关键思路和调试的方法论,后续在解决 Spring 和 Netty 相关的问题,即使之前没有研究过相关模块,也能够很快定位并解决问题,接下来就进入了成熟期。
2.3 成熟期:19年 ~ 今
从 2019 年到现在,处在成熟期,这段时间开始大量阅读其他开源框架源码,排查各类疑难杂症,并逐渐开始探索计算机底层原理的实现。
这段时间周末没事就在家研究一些开源框架的实现,比如 Dubbo、Mybatis 及工作中涉及到的一些核心框架。我的研究方式是,每次研究之前,都给自己抛出一个问题,比如:Dubbo 的服务发现是怎么做的,然后花一个下午或一个晚上的时间通过源码找到完整的答案。
经过成长期的磨练,到这个时期,快捷键已形成了肌肉记忆。可能我无法快速说出某操作的快捷键,但是能用手指本能地按出来。快捷键的肌肉记忆给我阅读和调试源码带来了巨大的帮助,当手速跟上了思维的速度之后,思维的连续性得到保障,每一次阅读源码都能够进入心流状态。
在探索 Dubbo,Mybatis 等其他开源框架的源码过程中,凭借过去的经验和调试技能,给我带来一个非常直观的心理感受就是:每次分析源码的过程就像是一次推理破案的过程,又犹如阅读一篇悬疑小说,在纷繁复杂的世界中抓住核心环节,厘清思路,最终水落石出。源码面前无秘密,一切都是公开的。
研究了一些开源框架之后,我发现很多框架最底层的原理其实大同小异(比如 redis、nginx、netty 的应用层的内存分配机制和线程模型的设计几乎是一致的),框架每过几年就会翻新一遍,没这么多时间去把所有的框架都去研究一遍。
这个时候需要问自己一个问题:每当遇到一个新的技术,如何很快掌握?
2021 年春节前开始思考这个问题,春节那段时间,得出结论:后续的技术生涯中,我需要去探索在未来几年甚至十几年那些不变的东西。
于是我将研究方向转向了计算机底层原理。其中一部分就是 Linux 内核,内核中有非常多的宝藏值得深挖,很多应用层的一些设计与内核设计同构,且有很多技术直接依赖于内核的实现,如 Docker。
虽然内核是 C 语言和汇编写的,而我是搞 Java 的,但是源码分析的思路和调试的技能是相通的,经过了一段时间的尝试,21年年底开始写 Linux 内核分析相关的文章(【原创】Linux 内核源码分析之进程概要及调度时机、【原创】Linux 内核源码分析之进程调度的逻辑),算是开始入门了吧。
内核远比我想象的要复杂得多,但是越复杂,探索的过程就越刺激。
今天是 2022 年元旦,给自己订个内核小目标:2025 年元旦前入门,2027 年元旦前熟悉,2032 年元旦前精通,10 年后来看,希望不要被打脸呀!
3 结语
本来这篇文章想重点写写阅读源码的关键思路和调试技能的,没想到写到最后成了源码回忆录,索性把干货部分放到下一篇文章中吧,欢迎大家关注公众号。