[toc]
如果您喜歡這份小冊,麻煩您分享給您的朋友哈。
## 一、如何閱讀源碼?
優質的開源項目,不論是從業務概念上的抽象,還是實實在在、反反復復的調優、驗證,很可能是凝聚了一個團隊幾年的心血,甚至有著龐大的體系。
開源的項目已經為軟件生態注入了強大的血液。一個優秀的團隊,務必有這樣的先行者——他們無懼未知、勇于先行,在縹緲的線索中逐漸抽絲剝繭、持續深耕,學習過往經驗、承前而啟后。這個過程中,搜集資料、解讀開源,便是一門程序員的必修課。
那我們如何有效的閱讀源碼呢?
### 源碼解讀基本流程
在總結源碼解讀思路之前,不妨先想一想我們是如何構建一個項目的呢?粗略的講,大概是這樣的步驟吧:

那么,解讀源碼的時候,其步驟也大體類似,只不過寫代碼的人不是自己罷了。根據以往源碼閱讀的經驗,我們大概可以總結出這樣一條經驗:
1. 把握模塊劃分;
2. 通過配置深入了解軟件功能;
3. 解讀配置加載流程;
4. 提出核心問題,見招拆招~
## 二、高效閱讀心法
### 把握核心結構
越是優秀的開源項目,其在模塊設計上更加注重解耦,各個模塊各司其職,才得以組成一個可持續維護的項目。閱讀源碼前,不防看一下系統提供的架構圖,對各個模塊的職責有一個基本的了解,并能基本理解作者對模塊劃分的依據。
### 站在巨人的肩膀上
今天你所遇到的問題,早在很久之前就有先驅者們探索過了。所以,我們一定要利用好互聯網上的資源,為自己將要涉足的這片“土地”有基本的了解。甚至可以先參考一下別人對這款軟件源碼的解讀,以便自己更好地找到學習的方向。
如果沒有,那你就是先驅者啦!我們也可以留下自己的腳印供后來人欣賞、借鑒~
### 提出問題,找尋問題答案
這樣可以帶有目的性地來閱讀源碼,效果往往會比較好。逐漸地,我們也會形成自己的一套提問的方法論。比如我會這樣提問:
- 先讀配置文件,了解配置文件核心參數的結構和含義。配置文件的結構凝聚的便是軟件功能的核心結構;接下來再去了解各個參數背后的含義,這樣我們便對該軟件基礎功能有了較為深入理解。
- 找出系統啟動的入口。
## 三、代碼精讀:踏上調試之旅
“**調試是源碼閱讀的最好方式**”,這句話放在源碼學習的過程中一點都不為過。
調試過程中,我們不僅可以結合業務操作對代碼入口的進行梳理。
另外,在了解業務的基礎之上,通過調試能夠讓我們直觀地看到程序在運行中的數據,這樣我們就可以更加深入了解作者的代碼設計和開發思路。
### 3-1 調試法思路
#### 倒序法
調試一般用到的源碼閱讀方法就是倒序法。熟悉Java堆棧日志信息的同學,很容易就能理解,問題一般出在**棧頂**的代碼里。這里要么有異常、要么有一條顯眼的日志。通過這里,我們再查看堆棧信息,就可以把握程序的執行邏輯了!
通過倒序法,我們可以精準打出一系列的斷點。最終我們還需要配合正序法,完成邏輯的串聯。
#### 正序法
正序法是用來把倒序法標記的源碼斷點串聯起來。配合功能測試,我們按照正序的方法的理解源碼的真正的執行邏輯。
### 3-2 有所痕跡
好記性不如爛筆頭。再強的理解能力,都比不上沉淀。我學習源碼的時候,一般會通過畫圖或者筆記的方式把走過的路記錄下來——它們好似我的腳印,等我回頭眺望的時候,總能夠給我以明確的指示。
#### 畫圖
用圖說代碼是一個學習源碼的不錯的方式:一來可以清晰剖析代碼結構,二來通過記錄源碼關鍵位置,回過頭來再看時節省時間,且有跡可循;三來可視化效果比較好,降低溝通成本~
接下來,我們查看一個Dolphinscheduler源碼解讀的案例。
>[danger] 閱讀源碼的同學可以移步:https://www.toutiao.com/i7025583458269479454/

#### 記錄關鍵的堆棧信息
堆棧信息就是代碼森林里面的坐標,記住這個坐標,我們便不再迷路。
### 3-3 掌握原理要看數據結構
舉個過往的例子,剛開始學習Netty的時候,總是會糾結于pipeline中的handler的執行順序,生怕放錯了順序,導致了錯誤的執行。因為在學習Netty的時候,教程中并沒有提出出站處理器和入站處理器的數據結構,而是云云了一大堆所謂的規則,諸如:
- 前面的入站處理器需要調用super.channelRead(ctx, msg)或者ctc.fireChannelRead(msg),消息才能向后方的入站處理器傳遞——所謂,“擊鼓傳花,不能有人偷懶”;
- ChannelHandler的執行順序:ChannelInboundHandlerAdapter是按添加順序,ChannelInboundHandlerAdapter則與添加順序相反。
這些總結最多只能算是“規則”或“特征”,如果我們陷入了記憶規則的思維模式上,我相信,學習編碼一定是個很累的過程。因為,再多的記憶也無法理解其本質。
還記得我們在中學時代就開始學習的數學中經常會提到兩個概念嗎——**定理**和**性質**。
**數學定理**:定理是指在既有命題的基礎上證明出來的命題,這些既有命題可以是別的定理,或者廣為接受的陳述,比如公理。
**數學性質**:是數學表觀和內在所具有的特征,一種事物區別于其他事物的屬性。
子涵認為,**定理更加偏向原理,性質更加偏向特征**。我們應該把握原理,因為通過原理來推斷性質,是一個水到渠成的過程。在學習編程的過程中,要想把握原理,就需要掌握其數據結構。

Netty消息處理的pipeline各個其實是一個“雙向鏈表”結構:讀消息的過程,就是next指針向后輪詢的過程,當該處理器是入站處理器時,執行讀操作;寫消息的過程,則正好相反。
我相信,把握了這個結構,我相信聰明的你一定可以隨心所欲地定義Handler的順序了。
>[danger] 轉載請注明出處~
- 寫在前面
- 如何閱讀源碼
- 第一部分 開源框架
- Netty
- 啟動過程
- SpringSecurityOauth2
- Quartz
- quartz啟動原理
- quartz定時調度任務觸發流程
- 第二部分 優質中間件源碼分析
- Canal
- Canal是如何偽裝為mysql的slave的?
- canal源碼調試
- Sentinel
- 核心概念梳理
- 滑動窗口實現原理
- jvm-sandbox
- jvm-sandbox-repeater
- Windows環境安裝
- 結果比對
- 第三部分 優質行業項目源碼分析
- 第一章 分庫分表實踐
- sharding-jdbc
- 第二章 DDD領域驅動
- 享同科技DDD開源框架
- J-IM
- 功能測試
- 悟空CRM
- 項目搭建
- 默認密碼
- dataX-web
- 項目搭建
- 部署報錯
- dolphinscheduler
- awescnb
- geek
- chrome插件-funds
- 優質開源項目備忘