前言
为什么要读源码
如果你看到一个新东西,却没有理清它的逻辑,直到打通你已熟悉的东西(学名叫已有的知识体系),那肯定是没有真正理解它。
直接目标——学习框架
- 浅层知识细节太多,极其容易遗忘。如果一想起某个框架,你只记得一些琐碎的使用细节,那么连“如何使用这个框架”这个技能本身,也终究是会失去的。
- 如果框架对你都是黑盒,那么你就不敢用
- 熟悉源码,是对一些“微言大义”的佐证。每个框架 在其官网都有一句/段的概括,若是不熟悉整个上下文,这段精炼的概括是很难读出感觉的。此外,直接附着在源码上的注释,通常也很精炼,文档上很难看到。
- 世界很奇怪,打败微信的不会是另一个微信;光靠写代码,也不会提高写代码的水平。只有输出没有输入是不行的,要不断的学习优秀源码的实现。
深层知识/感觉才是有价值的
只有深层知识才可以通用,通用很重要
- 通用是必要的,对于java来说,如果只会spring + mybatis等入门框架,那么留给你的就是一些简单的后台系统(业务级的系统),你永远无法去做部门级、公司级、apache级的项目。
-
通用是有很大好处的,你学习一个新的东西会越来越快。如果你曾经精研过netty的io 原理,那么当你碰到kafka 的io 部分时,可以一笔跳过。
东西都是共通的,认知的几点规律 欧几里得的《几何原本》,从五条公设和五个公理出发,经过层层演绎推理,竟能推出整整一本书的内容。 当你把分层、异步、反应式这些基础的东西 理解透彻后,分析一个框架的源码就是一两天的事情。虽然短时间内增大了学习负担,但一旦理解透彻,疑惑不在脑中徘徊,长期来说省去了纠结、疑虑和google的时间。源码的学习 可以反哺源码学习的能力,从程序员的职业生涯来讲,成长来自解决足够复杂的事情,这需要你有足够高的学习和工作效率,决不能将工作产出绑死在工作时间上,学习源码是提高专业工作效率的重要部分。
如果不深挖一下,一个java开发很少有机会认识到学习linux 有多么必要。
分析方法
前期准备
- demo例子
- 如果条件允许的话,最好能熟练使用框架。使用的过程中最好积累一些疑问,以作为分析源码时的切入点,在分析过程中想办法解决这几个问题。
- 阅读官方文档,搜索一些博客,对其主要设计、理念心中有数
- 了解下框架涉及的一些底层技术,比如NIO等
- 程序=数据结构+算法,识别其数据部分(也就是输入输出是什么),猜测其核心逻辑(算法)
分析过程
- 多画图,相对文字而言,图的信息密度更高
-
类图,所有用面向对象思想实现的框架都可以画类图,类图反映了代码的组织。一个框架如果代码量很大的话,一定要解决一个事情,即代码和数据是如何分散在各个小单元的,类图通常反应了作者对框架所解决问题的逻辑抽象。画类图有几个注意点
- 抓大放小
- 因为Java 各种设计模式,表象跟意图经常错位。比如A 有一个B成员,有时不能画为 A和B 是聚合关系
- 同一个意图的几个类,建议标上一致的背景色,突出功能域
- 序列图。包括初始化流程,和主干流程。 对源码分析进行整理浓缩,跟踪主要路径,直到打通到你已经熟悉的知识。以java为例,一个序列图的尾部,通常是类似java/io 等已熟知的类。
- 重要的不是画这些图,而是以这些图为抓手,串一个下整个过程,分析的过程才是最重要的,切忌把画图手段当成目的。找到感觉,积累成功的心理体验。
类图和序列图系统分析 一个框架示例 Jedis源码分析
一些技巧
- 只分析主要功能的主要流程,忽略异常处理、特殊逻辑处理等。没错,80%的代码都没干“正经”事。有兴趣可以找源码0.0.1 版本的代码看下。
- 能有一段较长的、可以集中注意力的时间
- 世界很复杂,但基础的逻辑真的很有限。源码很复杂,但基础的原理真的很有限。
- 在你学习一定数量的框架之前,你收到的全是负反馈(因为有那么多不会的),但一旦越过瓶颈点,尤其是你学过一些很难的框架之后,再去看一些简单框架的源码,你就会有一种“藐视敌人的英雄气概”。无论做什么事情,成功过一次很重要。
- 不断去做,以至于成为本能。源码分析的多了,会形成一种直觉,从繁杂的表象下提取关键、有效信息的直觉
- 每个人的背景知识是不一样的,写一篇文档,以自己的视角重新串一下整个框架。
- 任何一个系统的设计都有功能和性能(泛化一下就是功能性和非功能性) 两个部分,识别系统模块属于哪个部分,有助于简化对系统的认识。通常,一个系统的最早版本只专注于功能,后续除非大的变动,后来的演化大部分都是为了性能上的追求
- 作者的代码不是一下子写出来的,你也不要试图一下子勘破所有门道。用分层、主次要矛盾的方法论去认知。
你要有一个武器库,而不是三板斧。