本文分享本人阅读java源码的思路。本文面向阅读源码的新人,说的比较简单。
我大学时不知道怎么阅读java源码,而且也不知道该怎么入手,经常在不同的类/方法调用之间绕的云里雾里,后来看《Spring源码深度解析》这本书,才可以说入门了。
如果你也不知道怎么读源码,希望这篇文章可以给你一个大致的思路。
本文主要说的是本人的思路,如果你自己已经养成自己阅读源码思路(与作者的思路不一致),那么选择合适你的做法就好了。
1. 目的
要带着目的来阅读源码,以免迷失在源码里,可以选择一个你感兴趣的功能切入(如spring如何构造bean),弄清楚这个功能是怎么实现的。
2. 调试
首先搭建好运行环境,开始调试代码。调试代码是阅读源码的一个重要手段。
可以在代码必经点打断点,然后利用idea的调试功能跟踪方法轨迹。
我说的代码必经点,就是完成功能必须经过的代码,在这些代码上打断点可以追溯方法调用轨迹,分析代码调用链路。

要了解spring如何构造bean,可以在bean的构造函数上打断点。
要了解spring如何注入bean属性,可以在set方法打断点。
要了解spring如何实现aop功能,可以在被增强的方法打断点。
如果你不清楚在哪个类/方法上打断点,可以先在网上查询相关资料,知道功能实现的大概流程(可以想想如果自己实现该功能会怎么做),就知道在哪些地方打断点了。
针对想要阅读源码的功能,多写几个demo,在不同的地方打断点,慢慢调试,就可以找到实现功能的核心类/方法,弄清楚这些核心代码(方法调用链路,对数据的处理等),就可以梳理出功能的实现流程了,到达下面说的第一阶段。
我后面的阅读Spring源码系列文章也会列出核心代码,大家在看文章时,可以在列出的核心代码上打断点调试,重点理解核心代码。
3. 循环渐进
阅读代码不是一件容易的事情。按照对源码的理解程度,个人理解可以划分为以下几个阶段。
第一阶段:了解功能的实现流程(比如方法之间的调用),理解核心代码。
第二阶段:理解框架怎么做到高内聚低耦合,可扩展的
这一阶段需要理解一些核心类的概念,还有核心接口负责实现的功能,不同接口功能怎么划分(接口隔离原则),接口的不同的实现类有什么区别等。
如spring的BeanDefinition概念,还有核心接口BeanFactory的功能,而HierarchicalBeanFactory/ListableBeanFactory都是它的子接口,又有什么区别呢?
了解框架的扩展机制也很重要,能帮助我们更好地了解和使用该功能。
如在spring的ioc功能中,构造bean,注入bean属性,注册到spring上下文中,这些主流程步骤是不变的,通用的。
但在一些特殊情况下,用户要实现一些特殊逻辑,这些逻辑是变化的,个性化的,如自定义属性的解析,bean要等某些属性注入后申请资源等。
一个合理的框架设计,需要满足用户个性化逻辑,但不能让个性化逻辑影响到主流程(开放封闭原则),
这时spring的扩展机制就非常重要了,如BeanPostProcessor,ConversionService,ApplicationListener。
第三阶段:站在整个框架上,看框架(或框架的某个功能点)优缺点,设计理念或算法。
比如使用spring ioc有什么好处
个人理解,比如管理应用的配置类,应用可以随时获取配置信息。
属性注入则可以降低耦合度,用户可以随时更换某一个功能的实现类,甚至组件(依赖反转)。
而其他框架,如dubbo,不使用spring,它如何管理配置信息呢?又如何管理用户扩展的功能类呢?(一对比,就知道spring ioc可以帮我们简化很多工作)。
还有,比如阅读dubbo源码,深入了解如何实现rpc框架,阅读sofa-jraft源码,了解raft算法的细节等等。
同时,我们也可以从源码中学习,如spring的扩展机制用到了什么设计模式,我们写代码时是否可以参考?
我很喜欢spring的扩展机制,主要是它划分可变代码和不变代码的思路很值得借鉴。
之前做过一个下单系统,一些个性化的客户下订单需要做一些特殊处理
之前的主要流程代码如下
if client = A
handerAClient
else if client = B
handleBClient
else
hanldeDefaultClient复制
代码耦合度非常高,而且每次接入新的(个性化)客户都要修改主要流程代码。
参考spring的扩展机制,代码修改为
handler = getClientHandler(client);
if(handler == null)
hanler = DefaultClientHandler;
hander.handle();复制
这样接入新的客户后,只要添加一个ClientHandler就可以了。
还有一点,读源码后,一定要有阅读框架源码解决问题的意识,如果框架源码抛出了一个异常,我们是可以通过看框架源码来解决问题的。
点击错误堆栈信息里的报错方法,idea就可以直接看到反编译的框架源码了,也可以在框架源码打断点,调试源码。
优秀的框架多数是经过完整的测试,出现错误的概率较低,多数是我们使用方法/配置错误导致,但通过调试框架源码也是帮助我们发现哪里使用出错了。
还有一些框架功能实现的细节,可能文档描述不清楚,也是可以通过调试框架源码找到答案的。
不要这样一看到框架里报错就不知所措,这很重要。
文章最后,附图一张