如何阅读源代码(建议收藏)

读源码是大多数程序员进阶的重要途径,最近了解到很多朋友反馈读了一些源码但是收获不是很大,看了一些源码总是半途而废,有很多困惑。

主要表现为:

整体概览:

在我看来,大多数人读源码收获不大的主要原因如下:

做事要“以终为始”,只有搞清楚读源码我们究竟想得到什么,我们才能避免“走马观花”最终将收获无多的尴尬场景。

读目的:该框架是为了解决什么问题?比同类框架相比的优劣是什么?这对理解框架非常重要。

读注释:很多人读源码会忽略注释。建议大家读源码时一定要重视注释。因为优秀的开源项目,通常某个类、某个函数的目的、核心逻辑、核心参数的解释,异常的发生场景等都会写到注释中,这对我们学习源码,分析问题有极大的帮助。

读逻辑:这里所谓的逻辑是指语句或者子函数的顺序问题。我们要重视作者编码的顺序,了解为什么先写A再写B,背后的原因是什么。

读思想:所谓思想是指源码背后体现出了哪些设计原则,比如是不是和设计模式的六大原则相符?是不是符合高内聚低耦合?是不是体现某种性能优化思想?

读原理:读核心实现步骤,而不是记忆每行代码。核心原理和步骤最重要。

读编码风格:一般来说优秀的源码的代码风格都比较优雅。我们可以通过源码来学习编码规范。

读编程技巧:作者是否采用了某种设计模式,某种编程技巧实现了意料之外的效果。

读设计方案:读源码不仅包含具体的代码,更重要的是设计方案。比如我们下载一个秒杀系统/商城系统的代码,我们可以学习密码加密的方案,学习分布式事务处理的方案,学习幂等的设计方案,超卖问题的解决方案等。因为掌握这些方案之后对提升我们自己的工作经验非常有帮助,我们工作中做技术方案时可以参考这些优秀项目的方案。

很多人读源码不顺利,效果不好,通常都会有些共性。

那么读源码通常会有哪些误区呢?

经常打游戏的朋友都知道,开局直接打Boss无异于送人头。

一般开局先打野,练就了经验再去挑战Boss。

如果开始尝试学习源码就直接拿大型开源框架入手容易自信心受挫,导致放弃。

经常打游戏的朋友也都知道,打游戏要讲究策略,随便瞎打很容易失败。

有些朋友决定读源码,但又缺乏规划,随心所欲,往往效果不太好。

我们知道很多小学生、初高中生,甚至很多大学生学习会出现眼高手低的情况。

有些人做题时并不是先思考,而是先看答案,然后对着答案的思路来理解题目。在这种模式下,大多数题目都理所当然地这么做,会误认为自己真正懂了。但是即使是原题,也会做错,想不出思路。

同样地,很多人读源码也会走到这个误区中。直接看源码的解析,直接看源码的写法,缺乏关键的前置步骤,即先自己思考再对照源码。

学习某个源码之前一定要对源码的基本用法有一个初步了解。

如果对框架没有基本的了解就直接读源码,效果通常不会太好。

一般优秀的开源项目,都会给出一些简单的官方示例代码,大家可以将官方示例代码跑起来,了解基本用法。

大家也可以去GitHub上搜索并拉取某个技术的Demo,某个技术的helloworld项目,快速用起来。

如Dubbo官方文档就给出了快速上手示例代码;轻量级的分布式服务框架jupiterREADME.md就给出了简单的调用示例。一些开源项目给出了多个框架的示例代码,如tutorials。

循序渐进是学习的一大规律。

一方面,可以先尝试阅读较为简单的开源项目源码,比如commons-lang、commons-collection、guava、mapstruct等工具性质的源码。

另外还可以尝试寻找某个框架的简单版,先从简单版学起,看透了再学大型的开源项目就容易很多。

可能很多人会说不好找,其实大多数知名开源的项目都会有简单版,用心找大多数都可以找到,比如Spring的简易版、Dubbo简易版。

先整体后局部是非常重要的一个认知规则,体现了“整体思维”。

如果对框架缺乏整体认识,很容易陷入局部细节之中。

先整体后局部包括多种含义,下面会介绍几种核心的含义。

大家可以通过框架的官方文档了解其整体架构,了解其核心原理,然后再去看具体的源代码。

但是很多人总会忽视这个步骤。

如轻量级分布式服务框架jupiter框架的README.md给出了框架的整体架构:

(图片来自:jupiter项目README.md文档)

对框架有了一个整体了解之后,再去看具体的实现就会容易很多。

先整体后局部,还包括先看项目的分包,再具体看源码。

(图片来自:jupiter项目结构)

通过项目的报名,如monitor、registry、serialization、example、common等就可以明白该包下的代码意图。

通过IDEA的函数列表功能,可以快速了解某个类包含的函数,可以对这个类的核心功能有一个初步的认识。

这种方式在读某些源码时效果非常棒。

更重要的是,如果能够养成查看函数列表的习惯,可以发现很多重要但是被忽略的函数,在未来的项目开发中很可能会用到。

下图为commons-lang3的3.9版本中StringUtils类的函数列表示意图:

比如一个大函数可能分为多个步骤,我们先要理解某个步骤的意图,了解为什么先执行子函数1,再执行子函数2等。

然后再去观察某个子函数的细节。

以spring-context的5.1.0.RELEASE版本的IOC容器的核心org.springframework.context.support.AbstractApplicationContext的核心函数refresh为例:

比如再去了解第7步的具体编码实现。

从设计者的角度读源码是一条极其重要的思想。体现了“先猜想后验证”的思想。

这样就可以走出“对着答案做题”的误区。

学习源码时不管是框架的整体架构、某个具体的类还是某个函数都要设想如果自己是作者,该怎么设计框架、如何编写某个类、某个函数的代码。

然后再和最终的源码进行对比,发现自己的设想和对方的差异,这样对源码的印象更加深刻,对作者的意图领会的会更加到位。

比如我们封装HTTP请求工具,获取响应后根据响应码判断是否成功,我们可能会这么写:

/***Returnstrueifthecodeisin[200..300),whichmeanstherequestwassuccessfullyreceived,*understood,andaccepted.*/valisSuccessful:Booleanget()=codein200..299发现和自己设想的不同,响应码的范围是[200..300)。

通过这个简单的例子,我们发现自己对HTTP响应码的理解不够全面。

另外通过这个源码我们也了解到了源码注释的重要性,通过源码注释可以清楚明白的理解该函数的意图。

很多优秀的开源项目都会用到各种设计模式,尤其是学习Spring源码。

因此,强烈建议要了解常见的设计模式。

了解常见设计模式的目的、核心场景、优势和劣势等。

要理解设计模式的六大原则:单一职责原则、开闭原则、依赖倒置原则、接口隔离原则、迪米特法则等。

在读源码时注意体会设计模式的六大原则在源码中的体现。

如jupiter1.3.1版本的org.jupiter.serialization.SerializerFactory类就体现了工厂模式。该类通过在静态代码块中使用SPI机制加载序列化方式并存储到serializersmap中,获取时从该map中直接取,实现了已有对象的重用。

大家可以通过《设计模式之禅》、《Java设计模式及实践》、《Headfirst设计模式》等来学习设计模式。

从设计模式角度阅读源码,可以加深对设计模式应用场景的理解,自己编码时更容易选择适合的设计模式来应对项目中的变化。

很多开源项目代码行数非常多,几十万甚至上百万行,想都读完并且都能记下来不太现实。

前面也讲到读源码读什么的问题,个人建议大家读核心的原理,关键特性的实现,高抽象层的几个关键步骤。

不要追求读每一行代码,甚至“背诵”代码,因为工作之后学习的目的更多地是为了运用,而不是为了考试。

我们以Guava源码commitid为5a8f19bd3556的提交版的CacheBuilder源码为例。

如果我们想了解expireAfterWrite函数的的用法。

可以通过读其注释了解该函数的功能,每个参数的含义,异常发生的原因等。对我们学习源码和实际工作中的使用帮助极大。

/***Specifiesthateachentryshouldbeautomaticallyremovedfromthecacheonceafixedduration*haselapsedaftertheentry'screation,orthemostrecentreplacementofitsvalue.*//省略其他**@paramdurationthelengthoftimeafteranentryiscreatedthatitshouldbeautomatically*removed*@paramunittheunitthat{@codeduration}isexpressedin*@returnthis{@codeCacheBuilder}instance(forchaining)*@throwsIllegalArgumentExceptionif{@codeduration}isnegative*@throwsIllegalStateExceptionifthetimetoliveortimetoidlewasalreadyset*/@SuppressWarnings("GoodTime")//shouldacceptajava.time.DurationpublicCacheBuilderexpireAfterWrite(longduration,TimeUnitunit){checkState(expireAfterWriteNanos==UNSET_INT,"expireAfterWritewasalreadysetto%sns",expireAfterWriteNanos);checkArgument(duration>=0,"durationcannotbenegative:%s%s",duration,unit);this.expireAfterWriteNanos=unit.toNanos(duration);returnthis;}通过单元测试学源码同样以学习6.1的函数为例,可以通过findusages找到对应的单元测试。

com.google.common.cache.CacheExpirationTest#testExpiration_expireAfterWrite可以执行在源码中断点,然后执行单元测试,了解源码细节。

publicvoidtestExpiration_expireAfterWrite(){FakeTickerticker=newFakeTicker();CountingRemovalListenerremovalListener=countingRemovalListener();WatchedCreatorLoaderloader=newWatchedCreatorLoader();LoadingCachecache=CacheBuilder.newBuilder().expireAfterWrite(EXPIRING_TIME,MILLISECONDS).removalListener(removalListener).ticker(ticker).build(loader);checkExpiration(cache,loader,ticker,removalListener);}从入口开始学源码如下面是常见的springboot的应用启动主函数:

@SpringBootApplicationpublicclassDemoApplication{publicstaticvoidmain(String[]args){SpringApplication.run(DemoApplication.class,args);}}我们可以从SpringApplication的run函数一直跟下去。

有些朋友可能会说,跟着跟丢了怎么办?

大家可以在源码中打断点,然后通过左下角的调用栈实现源码的跳转,可以通过“dropframe”实现。

可以使用IDEA自带的类图了解核心类的源码的关系。

如下图为fastjson的核心类的类图:

可以使用StacktracetoUMLIDEA插件绘制错误堆栈的时序图,了解源码的执行流程。

推荐大家安装SequenceDiagramIDEA插件,读源码时可以查看调用的时序图,对理解源码调用关系帮助很大。

强烈推荐大家安装codota插件(支持Eclipse、IDEA、AndroidStudio)通过该插件或对应的Java代码搜索网站。

如下图所示,我们安装好codota插件后,想了解org.springframework.beans.factory.support.BeanDefinitionRegistry的registerBeanDefinition函数用法。

这对我们了解该源码的功能和用法有极大的帮助,我们实际开发中也可以多用codota来快速学习如何使用一个函数。

比如我们想研究某段源码的变动,可以拉取源代码,查看Git提交记录。

比如我们想研究某个感兴趣类的演进,直接选取该类,查看提交记录即可。

下图为commons-lang项目的,StringUtils工具类的一个变更记录:

通过变更记录我们可以学习到早期版本有哪些问题,如何进行优化。

issues是学习源码的重要途径,是我们提高开发经验的一个重要途径。

如果我们想深入学习某个开源项目,可以翻阅历史issues。

针对具体的issue中涉及的具体的问题入手了解大家对该问题的看法,学习问题的原因和解决办法。

着重了解有多种方案时作者进行了何种考量,做出了什么取舍。

如AddImmutable*Array.reverse()#3965:

当我们对某些源码设计感到困惑时,可以在Google或者StackOverflow上搜索问题的原因,往往会有些意外收获。

我们在读源码时经常会遇到类似下面的这种写法:

org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#startWebServer

看似很小的细节,隐含着一个优化思想。这就需要借助反编译大法,在字节码层面去分析。

详细解读参见《为什么要推荐大家学习字节码?》。

总之,读源码要着重思考,思考为什么这么设计?可能的原因是什么?然后去验证。

THE END
1.阅读源码的经验总结如何阅读第三方开源库 选择一些当下热门、学习价值高的第三方开源库,我认为最值得学习的第三方开源库是Volly,开源项目解析中也有对Volly的解析。 热门的第三方开源库,网上会有很多源码解析文章,首先在网上找一些源码解析文章来看看,不要忘记,我们的宗旨之一“高效”,这样就可以快速的对项目的整体框架有一个大体的了解https://www.jianshu.com/p/be86e5678252
2.如何学习源码如何学习优秀的源码如何学习源码 一、程序员的层次划分(本文只针对学习源码部分) 1、只关注项目本身,不懂就baidu一下。 2、除了做好项目,还会阅读和项目有关的技术书籍,看wikipedia。 3、找一些开源项目看看,大量试用第三方框架,还会写写demo。 (要解决什么问题?如何实现的?)https://blog.csdn.net/shengyin714959/article/details/142281091
3.如何较好的学习框架底层源码?都有自己的优势和特点,在国内TP确实用的很多,我想说的是具体学习哪个框架并不重要,我们需要选择一个安安心心的学好他的底层(如果您时间比较充裕的话,全部学习也是可以的,哈哈),因为你会了一个框架之后,其他框架你自学下很快就会上手,因为框架的核心思想基本是相通的,本文章我就拿TP来举例,我们如何学习他的源码呢https://www.imooc.com/article/284124
4.Vue源码学习之响应式是如何实现的vue.js最近接触了vue.js,一度非常好奇vue.js是如何监测数据更新并且重新渲染页面,这篇文章主要给大家介绍了关于Vue源码学习之响应式是如何实现的相关资料,需要的朋友可以参考下+ 目录 GPT4.0+Midjourney绘画+国内大模型 会员永久免费使用!【 如果你想靠AI翻身,你先需要一个靠谱的工具!】 前言 作为前端开发,我们的日常工作https://www.jb51.net/article/225377.htm
5.还不会Vue2.x源码本地调试!一前言由于自己最近准备学习vue的由于自己最近准备学习vue的源码,所以首先我得知道怎么样去本地调试vue得源码。后续也会把学习中遇到得问题、校验梳理成文章,也当作自己的学习笔记。 写在前面,我看的版本是"version":"2.6.14" 二、如何进行本地调试 首先我们找到vue2的源码地址进行本地clone https://juejin.cn/post/7081983962339508261
6.面向学生的.NET学习使用C#编程语言编程学习如何编写 C# 代码 嗨朋友们! 学习编码可能令人生畏。我们将随时为你提供帮助。 开始 获得认证 使用与freeCodeCamp合作进行的新基础 C# 认证,展示你的 C# 知识。该认证是全面的、可全球访问的,最重要的是,它是免费的,可确保世界各地的学习者都能从针对Microsoft Learn的可靠 C# 培训中获益。https://dotnet.microsoft.com/zh-cn/learntocode
7.RocketMQ消息积压,异步方案,缓存策略解决方案如何入手学习源码 最核心的一点就是查看官方文档 官方文档是所有技术中 最权威,最齐全的一个资料聚集地 有些翻译中文的网站,可能会做到更新不及时,所以还是建议直接看英文文档,借助翻译即可。也可以锻炼英文水平 首先要掌握这个技术的整体结构,有哪些功能特性,涉及到的关键技术、实现原理和生态系统等等。掌握了这些,对https://developer.aliyun.com/article/932643
8.idea看python源码mob64ca12f3496a的技术博客在上面的代码中,使用requests库获取API数据时,可以按住Ctrl并点击get函数,将打开get函数的源码,让你更好的了解它的实现逻辑。 第六步:理解和学习源码 在你打开Python源码后,仔细阅读代码及其注释,可以发现大多数库都包含详尽的解释。这会帮助你了解函数的功能与实现。 https://blog.51cto.com/u_16213443/12795867
9.源码时代成都IT培训重庆UIh5Java培训不敢去怎么办?毕业就拿近万元offer!现在的应届生都这么强?在源码毕业后,能进大厂吗?答案来了!狂欢7天7夜!源码时代11周年庆超燃来袭源码时代天府校区正式开课!2021源码时代课程更新、服务升级、就业加速:新价目标准将于4月1日正式执行 源码时代学习环境 硬核设施,舒适的环境,铸就你的美好未来https://www.itsource.cn/
10.人类高质量Java学习路线一条龙版做一个完整的项目的确很不容易,建议大家根据自己的时间、兴趣选择较新的、有配套源码的教程,保持耐心。 如何选择编程学习资源,可以看下我的原创文章:https://mp.weixin.qq.com/s/mlMql9RJCd7THt6rpGb8UA 下面推荐一些优质的、较新的项目实战视频教程 + 50 套项目源码。 https://xie.infoq.cn/article/a9fd4615c281e8ca41840ce37
11.北京大学金芝教授受邀出席云南省金芝专家工作站揭牌仪式并作学术金芝教授作源代码表示学习的报告 揭牌仪式结束后,金芝教授主要围绕源代码表示学习为软件学院师生作科研报告,详细介绍了深度学习技术如何赋能源代码分析工作。金芝教授通过主题突出的精彩报告,围绕代码表示学习发展历程及其重要意义和代码表示学习方法等方面同师生们进行了深入交流和研讨互动。针对师生提问,金芝教授给予了深入详http://www.sei.ynu.edu.cn/info/1056/2111.htm
12.macd指标背离公式源码(学习)博客macd指标背离公式源码(学习) 一、MACD顶底背离副图 DIFF:EMA(CLOSE,12) - EMA(CLOSE,26);DEA:EMA(DIFF,9);MACD:2*(DIFF-DEA),COLORSTICK;A1:=BARSLAST(REF(CROSS(DIFF,DEA),1));B1:=REF(C,A1 1)>C AND REF(DIFF,A1 1)A2:=BARSLAST(REF(CROSS("KDJ.K"(9,3,3),"KDJ.D"(9,3,3)),1))http://blog.eastmoney.com/yudi010/blog_220210785.html
13.助记词盗u秒u源码转地址转私钥可直接对接假钱包app端源码仅供学习交流使用,一切法律后果均与本站无关。 助记词转地址 + 余额更新 + 一键账号余额一键归集 大于多少u自动转走 可直接对接假钱包,具体方法已经写在教程里了 教程 本系统集合助记词转地址 + 余额更新 + 一键余额一键归集 安装教程php7.2 mysql5.6 php安装gmp扩展 安装nodehttps://www.jianshu.com/p/https://yiqucode.com/qukuailian-3696.html
14.Git--distributed-even-if-your-workflow-isnt Git is afree and open sourcedistributed version control system designed to handle everything from small to very large projects with speed and efficiency. Git iseasy to learnand has atiny footprint with lightning fast performance. It outclasses SCM tools https://git-scm.com/