最近,为了提高团队成员技术水平,考察了大家源码阅读情况。作为第一期任务,选择了spring框架,范围是spring-beans,spring-context,spring-core,以及spring-web。考核方式为:了解spring框架作用、核心概念,并选择感觉最重要的几个类进行详细阐述。
从效果上看,距离预期还有很大差距。很多人还是不清楚到底为什么要看代码,怎样去看,看过之后收获什么。所以,本文给一些看源码的建议,和可供参考的方法。
我们预期是通过看源码,了解目标框架/工具的运行原理和结构设计。对于成熟、出色的框架,那么代码一般是经过锤炼的。通过深入阅读,可以看到其中的优秀设计,良好的代码规范,合理的数据结构应用,设计模式运用。诸如netty等框架,也会包含网络、通道、并发等优秀的处理方案。这些都是我们值得学习的地方。
通过上面的阐述,那么我们预期的目标就是:
1、目标框架/工具的原理和设计深入理解;
2、代码规范、设计模式学习借鉴
3、问题解构、方案架构设计思路
在选择要研究的源码,优先推荐技术体系内,应用较多且成熟的框架/中间件。这样选择的原因:
1、源码质量有保障。我们希望看源码是尽可能吸收好的地方,同时也不希望染上不好的代码习惯;
2、对框架有一定了解;因为平时有应用,所以对其不是一无所知。正好在研读的过程中,与我们的使用方式、官方最佳实践能够进行对照验证,甚至一些已知可能的bug也可以进一步了解。如果是不熟悉的,那么我们很难快速进入这样的状态;
3、官方资料/文档相对较多,可以作为参考资料,这样在遇到问题时,可以去快速验证想法的正确与否
一些例子:比如我们使用的语言是java,那么ssh框架就几乎是首选,尤其是spring,几乎是对Java开发者要求必须掌握的内容;如果想要看中间件,那么消息队列如kafka、rocketmq都是不错的选择;除此之外,rpc框架如dubbo,网络通信如netty,数据库mysql(可以与mysql技术内幕、或官方文档搭配学习),缓存redis都可以作为第一选择。
在选择了目标之后,接下来就是怎么看了。方法也同样重要。
首先,我们肯定不能直接铺开所有,这会导致进度的不可控,也不利于整体脉络、结构的梳理。所以,可以从最基础的特性、概念开始。还是以spring为例,最重要的两个概念:IOC 和 AOP。我们首先选择IOC。IOC指依赖翻转,那么这可以包含多少问题?先自己思考几分钟,这都涉及哪些子问题,
1,
2,
3,
好,我们看答案:
你是否想到了上面的全部?如果没有,那么覆盖了多少?如果差的比较多,那么说明尽管对这个领域有一点了解,但并不深入,那么接下来就需要去弥补这个缺陷。
ok,现在了解了涉及到哪些问题,那么我们将在看源码的过程中去逐个验证。
框架的代码大多都是几万行、几十万行的量级。从类的角度来看,也会有数百上千个类来支持其背后的设计。我们不可能全部看一遍,而且也没有必要。所以,找到主流程入口,以此为切入点,去梳理整个流程是不错的选择。
在主流程清晰之后,再去逐渐扩展,主次分明。
在技术领域覆盖上,同样存在着这样的选择。是先深入一项,还是全面铺开,优先技术广度?
在这个问题上,我个人的建议是在具备工作能力的前提下(不影响我们日常工作进度),优先深入一门,集中攻克核心问题,之后再去钻研其他;在语言基础、框架、消息中间件、数据库、缓存等每个领域都有一项最常用的技术有了一定深度的了解之后,再扩展自己的知识广度。好的设计往往是相通的,同一领域的不同技术之间,也往往存在着很多类似的设计,并基于各自的目标适用领域在方向上有所取舍。而在我们对其中一项具有相当理解程度的基础之上,才能够融会贯通。
阅读源码的同时,最好记录下一些东西。例如关键流程的梳理结果、核心类的设计方式、关键问题的答案/推测、还存在疑惑的问题等,这些是我们后续迭代深入的依据,也能加深印象。
继续以spring源码阅读为例。首先,了解代码整体结构之后,可以得到大概的设计结构:
然后,通过阅读AbstractApplicationContext容器,可以得到下面的refresh方法执行流程:
类AnnotationConfigApplicationContext的结构图(继承、实现关系):
在输出上述产物的过程中,会对阅读的内容进行整理,也就是所谓的”结构化“。有了这样的输出,我们就可以在后续再次回溯,或在向其他人讲述的过程中,不断深化这些结构知识,并最终落实到我们的脑海中。
“零散的知识点不是自己的,知识体系和方法论才是。”