Skip to content

为什么要学习源码?

学习优秀的代码实践

如果我们沉浸在自己的世界,整天 CRUD,实际是很难提高自己的编码能力,重复编码提升的不过是熟练度罢了!

如果我们想要写出质量更高、扩展性更好的代码,我们要做的事情非常简单:看一些技术大佬是怎么写的,模仿就完事了。

这个模仿不同于照葫芦画瓢,我们需要搞懂优秀设计背后的原理。

那怎么检验自己是否掌握了呢?很简单,看自己能不能在后续的编码中实践就好了。但是,切记不要为了用“好的编码实践”而用,一切要结合业务实际需要。

一些不错的开源项目,都是一些技术大佬们几个月甚至是几年的成果。只要肯花时间看,我们一定能从源码中学到很多东西。

我们需要重点关注源码中的这些点:

  • 如何抽象接口的?
  • 如何运用设计模式的?
  • 如何实践 SOLID 软件设计原则的?
  • 有哪些优秀的编码实践?
  • ......

借鉴

如果我们想要设计一个类似的框架或者轮子的话,参考已有的优秀框架不失为一个好手段。俗话说的好:“他山之石可以攻玉”。

我们平时接触到的很多开源项目都是例子,比如阿里开源的消息队列 RocketMQ 就借鉴了 Kafka 。

面试需要

据我观察,大部分真正愿意去看源码的朋友都是为了面试。这些朋友会找到对应框架比较重要的部分来学习源码,拿 Spring Boot 来说的话,就是 Spring Boot 启动流程、自动配置原理...。

确实,短时间内突击源码,我们一定要重点关注那些重要的地方。

但是,这种为了面试而突击源码的方式,往往很难真正学到源码的精髓,能收货的东西也会很有限。

项目需求

很多时候,我们阅读源码是因为项目需要。

比如说我们的项目在前期引入了某个开源框架,但是到项目中期的时候,我们发现这个开源框架并不能很好地满足我们的需求,甚至说还有一些小 bug 。与这个开源框架相关的负责人员交涉之后,我们的反馈并没有得到相应。这个时候, 我们就需要自己去实现某些功能以及修复某些 bug。想要做这些事情的前提是:我们当前对这个开源框架某一块的源码比较熟悉了。

源码面试这块会怎么问?

首先,你需要明确一点的是:随便一个框架的源码都 10w+行了,都看一遍是不可能的。你需要挑选比较重要的地方看。

拿 Spring/Spring Boot 源码举例:你一定要去看 IOC 和 AOP 具体的实现,要知道一个 Spring Bean 是如何一步一步被创建出来的。一定要搞清 Spring Boot 是如何实现自动配置的。

源码面试这个不会太细节。如果你知道的话一定是加分项,不知道的话不一定就会被 pass。不过你写简历的时候尽量写清楚点,写清楚自己看过哪部分的源码。

平时学习过程中,有时间的话可以多看看源码,对于提升自己的能力非常有帮助!

如果你不知道阅读什么源码的话,可以先从 JDK 的几个常用集合看起。另外,我比较推荐看 Dubbo 的,因为感觉会稍微相对容易一点,模块划分清晰,注释也比较详细。搞清楚了 Dubbo 基本的原理之后,看起来就没那么吃力了。

有哪些值得阅读的优秀源码?

下面有部分内容是摘自朋友写的一篇文章:《如何提升代码质量 - Thoughtworks 洞见》

JDK

为什么要看 JDK 源码?

  1. JDK 源码是其它所有源码的基础,看懂了 JDK 源码再看其它的源码会达到事半功倍的效果。
  2. JDK 源码中包含大量的数据结构知识,是学习数据结构很好的资料,比如,链表、队列、散列表、红黑树、跳表、桶、堆、双端队列等。
  3. JDK 源码中包含大量的设计模式,是学习设计模式很好的资料,比如,适配器模式、模板方法模式、装饰器模式、迭代器模式、代理模式、工厂模式、命令模式、状态模式等。
  4. JDK 源码中包含大量 Java 的高阶知识,比如弱引用、Unsafe、CAS、锁原理、伪共享等,不看源码是很难学会这些知识的。

JDK 源码阅读顺序

  1. java.lang 包下的基本包装类(Integer、Long、Double、Float 等),还有字符串相关类(String、StringBuffer、StringBuilder 等)、常用类(Object、Exception、Thread、ThreadLocal等)。
  2. java.lang.ref 包下的引用类(WeakReference、SoftReference 等)
  3. java.lang.annotation 包下的注解的相关类
  4. java.lang.reflect 包下的反射的相关类
  5. java.util 包下为一些工具类,主要由各种容器和集合类(Map、Set、List 等)
  6. java.util.concurrent 为并发包,主要是原子类、锁以及并发工具类
  7. java.iojava.nio 可以结合着看
  8. java.time 主要包含时间相关的类,可以学习下 Java 8 新增的几个
  9. java.net 包下为网络通信相关的类,可以阅读下 SocketHTTPClient 相关代码

源码量那么大,不要妄想一口气都看完。最好符合你当前的目的,比如你想搞懂多线程,你就主要看 JUC,想搞懂 IO 就多去看 NIO,想看常量池就去看 ClassFileParser。看模块的时候,要注意接口大于一切,或者说函数大于一切。先不要妄想搞懂所有细节,先找几个比较关键的函数,搞懂函数的作用(比如应该仔细分析一下函数名称和参数名称)然后再往下进行。

在看 Java 类库的时候要多注意类是不是 abstract 的,是不是用的模板方法,多关注函数前的修饰词,这一般说明这个函数是给谁用的。多注意这些细节而不是傻傻过一遍逻辑,能从里面学到不少关于设计的东西。还可以注意什么地方是为了之前的设计而委曲求全的做法,毕竟一个这么多年的类库,肯定不是什么地方都是完美的。

JDK 源码一定要看 Java 并发相关的源码, Doug Lea 的并发源码比较漂亮,一行行都是精华,非常值得阅读学习。

Spring

Spring 是一个开源的设计层面框架,它解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。包括在此基础上衍生的 Spring MVC、 Spring Boot 、Spring Cloud 等,在现在企业中的应用越来越广泛。无论是设计思想,代码规范,还是设计模式,接口设计,类加载,都是非常优秀的源码。

个人学习心得如下:先去看视频,大概熟悉一下 Spring 的使用情况,然后再去学习源码,此处可以阅读《Spring 源码深度解析》,除了看书之外,记得打开 IDEA 查看对应的源码,如果能调试看看具体调用逻辑那就更好了。

Google Guava

Google Guava 是 Google 公司内部 Java 开发工具库的开源版本。Google 内部的很多 Java 项目都在使用它。它提供了一些 JDK 没有提供的功能,以及对 JDK 已有功能的增强功能。其中就包括:集合(Collections)、缓存(Caching)、原生类型支持(Primitives Support)、并发库(Concurrency Libraries)、通用注解(Common Annotation)、字符串处理(Strings Processing)、数学计算(Math)、I/O、事件总线(EventBus)等等。

Netty

Netty 是一个优秀的开源网络编程框架,我们平常经常接触的 Dubbo、RocketMQ、Elasticsearch、gRPC 等等都用到了 Netty。

Netty 中使用了大量的设计模式以及优秀的设计原则。

Dubbo

Dubbo 是一款优秀的国产 RPC 框架,其 SPI 自适应扩展、负载均衡实现、集群实现、服务调用过程等部分的源码都非常值得阅读和学习。

保姆级别的源码阅读教学

如何高效阅读项目源码

⚠️ 注意:

  • 阅读源码之前,一定要先熟悉项目。你连 Dubbo 怎么使用、RPC 是个啥都不知道,就直接去看 Dubbo 源码的话,不是纯属扯淡么?
  • 阅读源码之前,一定要对项目源码使用的技术有一个最基本的认识。

从了解并使用项目开始

开始看源码之前,自己花一些时间阅读以下官方的文档、使用教程。如果官方文档是英文的话,也可以找一些国人写的博客看看。不知道项目是用法和用途的就去看项目源代码的行为,无疑是在黑夜中穿针。

站在最外层概览项目设计

阅读源码之前,我比较推荐先站在最外层去熟悉项目整体架构和模块分包。掌控全局之后,我们方能以一个更正确的姿势畅游源码的世界。

比如,我在看 Dubbo 源码之前,我就首先花了大量时间熟悉了 Dubbo 的模块分包,这个在其官方文档上介绍的就非常详细。

从某个功能主线/问题出发研究项目源码

一个比较成熟的项目的源码量是非常多,我们不可能都看完。比较推荐的方式就是通过一个功能主线(比如 Dubbo 是如何暴露服务的?)或者问题(比如 SpringBoot 的自动配置原理?)出发。

学会使用官方提供的 Demo

一般情况下,项目源码已经自带了一些 Demo 我们可以直接使用。这样可以方便我们:

  • 检验源码阅读环境是否搭建成功。
  • 调试项目。

比如在 Dubbo 项目源码中,我们找到 dubbo-demo 这个文件夹,里面包含了 3 种不同类型(xml、api、annotation)使用方式的 demo,可以帮助我们节省掉大量写 Demo 的时间。

有哪些对阅读源码有帮助的建议

学习常见的设计模式、设计原则

一个优秀的开源项目一定会不可避免使用到一些设计模式,如果我们提前不了解这些设计模式的话,会加深自己理解代码的难度。

另外,项目的代码还应该满足一些设计原则。对于,面向对象编程来说,下面这些原则都是我们应该非常熟练的。

  1. 面向对象编程的思想(继承、封装、多态、抽象)
  2. 面向对象的七大设计原则:
  • 单一职责原则(Single Responsibility Principle, SRP)
  • 开闭原则(Open Closed Principle,OCP)
  • 里氏代换原则(Liskov Substitution Principle,LSP)
  • 接口隔离原则(Interface Segregation Principle,ISP)
  • 依赖反转原则(Dependency Inversion Principle,DIP)
  • 合成/聚合复用原则(Composite/Aggregate Reuse Principle,CARP)
  • 迪米特法则(Principle of Least Knowledge,PLK,也叫最小知识原则)
  1. 软件设计的三大原则
  • DRY(Don’t Repeat Yourself)原则:不要重复你自己
  • KISS( Keep It Simple/Stupid)原则:保持简单易懂
  • YAGNI ( You Ain’t Gonna Need It)原则 :不要进行过度设计

学会看测试类

测试类一方面可以说是对代码的稳定性的保障,让我们对自己写的代码更放心。另一方面测试本身也是对代码的一个说明,因此,很多人都会说:“好的测试即是文档”。通过测试类,我们可以很清楚地知道某一块代码具体是在干嘛。

学会调试

通过调试,我们可以更直观地看到调用逻辑关系。通过变量信息,可以更直观地看到数据的变化过程,这对于我们理解代码以及找 bug 都是非常有帮助的。

掌握 IDE 常用的快捷键

熟悉常用的快捷键在源码阅读中非常有必要!这个是必须要会的。

比如在 IDEA 中我们通过 command+o(mac)或者 ctrl+n(win/linux)即可搜索类以及文件

通过 command+f12(mac)或者 ctrl+f12(win/linux)即可查看类的结构(函数、变量)

使用一些插件辅助自己

有一些插件可以帮助我们理清源码的调用逻辑。比如 IDEA 插件 SequenceDiagram 就可以帮助我们一键生成方法的时序图。

相关阅读:《安利一个 IDEA 骚操作:一键生成方法的序列图》

手撸一个简易版

我们可以在学习某个具体的框架源码之前,自己先手撸一个简易版的框架。

就比如我们学习 Dubbo 源码之前,我们自己撸一个简易版的 RPC 框架。

自己动脑思考该怎么设计,功能该如何实现。

做了这些尝试之后,我们再去看别人写的源码,收货一定会非常大!

文章来源于自己总结和网络转载,内容如有任何问题,请大佬斧正!联系我