首頁>技術>

原始碼閱讀的意義

計算機技術和通訊技術的蓬勃發展催生了一批又一批的軟體開發者。對於軟體開發者而言,學校的教科書、網上的培訓影片都是非常好的入門資料。正是這些入門資料,幫我們打下了軟體開發的基礎。

資訊科技的飛速發展也帶來了許許多多的新概念,物聯網、區塊鏈、人工智慧、雲計算……層出不窮的新概念為我們描繪出一幅幅壯美的藍圖。介紹這些概念的書籍也如雨後春筍般不斷湧現。

然而,在基礎和藍圖之間卻有著巨大的知識斷層:我們很容易找到用來夯實基礎的入門書籍,也很容易找到用來闡述藍圖的分析文章,卻鮮有資料告訴我們如何從基礎開始構建出藍圖中的雄偉建築。於是,眾多的開發者迷失在了基礎和藍圖的知識斷層中,如同一個手握鐵錘的建築工人看著摩天大樓的規劃圖卻不知從何下手。於是有人選擇了放棄,繼續在增、刪、改、查中沉淪;有人選擇了摸索,不斷在重構改版中掙扎。

本文的目的不是幫開發者構建軟體開發的基礎,也不是向開發者描繪新概念的藍圖。本書是為了給開發者指引一條從基礎到藍圖的前進道路,幫助開發者具備在紮實的基礎上建造藍圖中雄偉建築的能力。

原始碼閱讀是理解和分析優秀的開原始碼,並從中積累和學習的過程。就如同剖析一座摩天大樓的內部構造般去分析一個優秀開源專案的組織劃分、結構設計和功能實現,進而學習、借鑑並最終應用到自己的專案中,提升自己的軟體設計和開發能力。

原始碼閱讀也是一個優秀軟體開發者必備的能力。如今絕大多數軟體都是團隊協作的成果,只有讀懂別人的程式碼才能繼續開發新的功能。即使是單兵作戰,也需要讀懂自己所寫的舊程式碼,之後才能開展新的工作。優秀的原始碼是最棒的程式設計教材,它能將整個專案完整地呈現給我們,使我們獲得全面的提升。原始碼閱讀能讓我們:

· 透徹地理解專案的實現原理;

· 接觸到成熟和先進的架構方案;

· 學習到可靠與巧妙的實施技巧;

· 發現自身知識盲點,完善自身知識儲備。

因此,原始碼閱讀是軟體開發者提升自身能力極為重要的手段。

原始碼閱讀的方法

原始碼閱讀對於提升開發者的技術能力大有裨益,可原始碼閱讀的過程卻是極為痛苦的。每一個優秀的工程專案都凝聚了眾多開發者的縝密思維邏輯;每一個優秀的工程專案都經歷了從雛形到成熟的曲折演化過程。最終,這些思維邏輯和演化過程都會投射和堆疊到原始碼上,使得原始碼變得複雜和難以理解。因此,原始碼閱讀的過程是一個透過原始碼去逆推思維邏輯和演化過程的工作。於是有人說讀懂原始碼比編寫原始碼更為困難,想必也是有一定道理的。

當我們閱讀一份原始碼時,需要面對的困難通常有:

· 難以歸納的凌亂檔案;

· 稀奇古怪的型別組織;

· 混亂不堪的邏輯跳轉;

· 不明其意的方法變數。

……可是,舒適能帶來的只是原地踏步。梳理這些凌亂檔案、理解這些型別組織、追蹤這些邏輯跳轉、弄清這些方法變數的痛苦過程,才是真正能讓我們獲得提升的過程。

原始碼閱讀的過程中也有一些技巧,掌握這些技巧能減少原始碼閱讀過程中的痛苦。“授人以魚,不如授人以漁”,本文會將原始碼閱讀中的方法和技巧總結出來,並希望大家將它們應用在其他專案的原始碼閱讀中。

我們先將一些基本的技巧介紹如下,更多的技巧將會在原始碼閱讀的過程中不斷給出。

· 除錯追蹤:多數情況下,當我們對某些變數的含義產生疑惑時,藉助開發工具的除錯功能直接檢視變數值的變化是一個非常好的方法。而且該方法還能指引程式碼邏輯的跳轉過程,對於理解原始碼極為有用。

· 歸類總結:優秀的原始碼都遵循一定的設計規則,這些規則可能是專案間通用的,也可能是專案內獨有的。在原始碼閱讀的過程中將這些設計規則總結出來,將會使原始碼閱讀的過程越來越順暢。

· 上下文整合:有些物件、屬性、方法等,僅僅透過自身很難判斷其作用和實現。此時可以結合其呼叫的上下文,檢視物件何時被引用、屬性怎樣被賦值、方法為何被呼叫,這對於瞭解它們的作用和實現很有幫助。

另外,還有一點不得不提,那就是要有一套強大的開發工具。有一套支援程式碼高亮顯示、錯誤提示、引用跳轉、斷點除錯等功能的開發工具十分必要,它能讓我們快速定位到所呼叫的方法,也能讓我們快速找到當前變數的引用,這些功能是進行原始碼閱讀所必需的。在 Java程式設計領域,強大的開發工具有 IDEA、Eclipse等,大家可以根據自己的喜好選用。

開源軟體

開源軟體(open source software)即開放原始碼軟體。這類軟體具有極強的開放性,其原始碼被公開出來供大眾獲取、學習、修改,甚至重新分發。也正因為其開放性,一些開源軟體吸引了眾多開發者參與其中,而這些開發者中不乏領域內的頂尖“大牛”。

以 Linux原始碼為例,截至目前它經歷過 21000多名開發者的 840000多次的提交。這充分說明了它是眾多開發者智慧的結晶,也從側面說明了該專案程式碼的嚴謹與優雅。

所以說優秀的開源軟體是進行原始碼閱讀的絕佳材料。

Github平臺是全球最為知名的開源軟體庫,眾多優秀的開源軟體就是在 Github平臺上協作開發的。我們可以到 Github平臺尋找自己領域內的優秀開源軟體,開展原始碼閱讀工作。圖1-1展示了 Java領域的一些優秀開源專案。

· apache/dubbo:一個高效能的遠端過程呼叫框架;

· netty/netty:事件驅動的非同步網路應用框架;

· spring-projects/spring-boot:一套簡單易用的 Spring框架;

· alibaba/fastjson:一套快速的 JSON解析、生成元件;

· apache/kafka:一套實時資料流處理平臺;

· mybatis/mybatis-3:一套強大的物件關係對映工具。

圖1-1 Java領域的一些優秀開源專案

除上述專案外,Github上還有眾多優秀的開源軟體供大家使用、學習,甚至參與開發。

MyBatis原始碼

經過不斷的篩選,本文最終選擇了開源軟體 MyBatis 作為原始碼閱讀的材料。這主要基於以下幾方面的考慮。

· MyBatis 專案悠久、成熟,且有著極廣的應用範圍,目前有十餘萬個開源專案引用它。

· MyBatis包括資料庫操作、物件關係對映、配置檔案解析、快取處理等眾多功能,涉及的知識面十分廣泛。

· MyBatis原始碼的程式碼量比較合適,如果程式碼量太大,則一本書難以細緻地講完;而如果程式碼量太小,則不能充分暴露原始碼閱讀過程中可能遇到的問題。因為 MyBatis是我們原始碼閱讀的材料,所以學完本書後,我們不僅會學到原始碼閱讀的方法和技巧,還會對 MyBatis 的實現原理、程式碼結構和設計技巧等了如指掌。最終,我們會成為 MyBatis 的精通者,這算是學習本書的額外收穫。因此,也可以單純地將本書作為一本 MyBatis原始碼解析書來看待。

本書所使用的 MyBatis版本為最新的穩定版 3.5.2,其開源專案地址為:

建議在閱讀本書時參考上述程式碼的中文註釋版,其開源專案地址為:

該版本在 3.5.2版本的基礎上增加了中文註釋。由於篇幅所限,很多書中沒有展示的程式碼及註釋也能在該版本中找到。因此這是閱讀本書時非常必要的輔助資料。

本文結構

在這一節中我們將對本書的結構進行簡要的介紹。同時,考慮到本文會涉及 MyBatis的相關檔案和大量的原始碼,我們也會對原始碼分析中涉及的術語進行規範。

背景知識

如果要說什麼是原始碼閱讀中最重要的因素,那應該是基礎知識。

如果不瞭解開源專案中的設計模式,則很難理清楚原始碼的結構;如果不清楚開源專案中的程式設計知識,則很難弄明白邏輯的走向。因此,掌握好開源專案中用到的相關基礎知識非常重要。為了更好地理解原始碼,在每個章節開始處將章節所述原始碼中涉及的知識介紹給大家。這些知識包括但不限於:

· 設計模式;

· Java基礎與進階知識;

· 專案用到的外部工具包;

· 專案依賴的外部類。

可以根據自己的知識儲備對這些背景知識進行學習,然後進行章節內原始碼的閱讀。

為了能夠更快地消化和吸收相關的知識,本文還準備了大量的示例,並將這些示例彙總成了一個開源專案 MyBatisDemo,其開源地址為:

檔案的指代

使用 MyBatis時,會涉及三類檔案。下面分別對這三類檔案進行簡要介紹,在本書後面的敘述中,將使用這些名稱來指代相應的檔案。

1.配置檔案

MyBatis的配置檔案為一個 XML檔案,通常被命名為 mybatis-config.xml。該 XML檔案的根節點為 configuration,根節點內可以包含的一級節點及其含義如下所示。

· properties:屬性資訊,相當於 MyBatis的全域性變數。

· settings:設定資訊,透過它對 MyBatis的功能進行調整。· typeAliases:類型別名,在這裡可以為型別設定一些簡短的名字。

· typeHandlers:型別處理器,在這裡可以為不同的型別設定相應的處理器。

· objectFactory:物件工廠,在這裡可以指定 MyBatis建立新物件時使用的工廠。

· objectWrapperFactory:物件包裝器工廠,在這裡可以指定 MyBatis使用的物件包裝器工廠。

· reflectorFactory:反射器工廠,在這裡可以設定 MyBatis的反射器工廠。

· plugins:外掛,在這裡可以為 MyBatis 配置差價,從而修改或擴充套件 MyBatis 的行為。

· environments:環境,這裡可以配置 MyBatis執行的環境資訊,如資料來源資訊等。

· databaseIdProvider:資料庫編號,在這裡可以為不同的資料庫配置不同的編號,這樣可以對不同型別的資料庫設定不同的資料庫操作語句。

· mappers:對映檔案,在這裡可以配置對映檔案或對映介面檔案的地址。

同時要注意,對配置檔案中的一級節點是有順序要求的,這些節點必須按照上面列舉的順序出現。在使用中可以根據實際需要選擇相應的節點依次寫入配置檔案。

程式碼1-1展示了一個簡單的配置檔案示例。

【程式碼1-1】

2.對映檔案

對映檔案也是一個 XML檔案,用來完成 Java方法與 SQL語句的對映、Java物件與SQL引數的對映、SQL查詢結果與 Java物件的對映等。

通常,在一個專案中可以有多個對映檔案。

對映檔案的根節點為 mapper,在 mapper節點下可以包含的節點及其含義如下所示。

· cache:快取,透過它可以對當前名稱空間進行快取配置。· cache-ref:快取引用,透過它可以引用其他名稱空間的快取作為當前名稱空間的快取。

· resultMap:結果對映,透過它來配置如何將 SQL查詢結果對映為物件。

· parameterMap:引數對映,透過它來配置如何將引數物件對映為 SQL引數。該節點已廢棄,建議直接使用內聯引數。

· sql:SQL語句片段,透過它來設定可以被複用的語句片段。

· insert:插入語句。

· update:更新語句。

· select:查詢語句。

程式碼1-2給出了一個簡單的對映檔案示例。

【程式碼1-2】

在對映檔案中,insert、update、delete、select 節點最為常見,這類節點統稱為資料庫操作節點,而節點的內容是一個支援複雜語法的 SQL語句,稱為資料庫操作語句。資料庫操作節點與資料庫操作語句如圖1-2所示。

圖1-2 資料庫操作節點與資料庫操作語句

3.對映介面檔案

對映介面檔案是一個 Java介面檔案,並且該介面不需要實現類。

通常情況下,每個對映介面檔案都有一個同名的對映檔案與之相對應。

在對映介面檔案中可以定義一些抽象方法,這些抽象方法可以分為兩類:

· 第一類抽象方法與對應的對映檔案中的資料庫操作節點相對應。

· 第二類抽象方法透過註解宣告自身的資料庫操作語句。當整個介面檔案中均為該類抽象方法時,則該對映介面檔案可以沒有對應的對映檔案。

程式碼1-3給出了一個對映介面檔案的示例。

【程式碼1-3】

因為對映介面檔案實際是一個 Java介面,所以有時也會稱其為對映介面。

方法的指代

1.方法名

在 Java程式中,常常會針對某一方法過載多個方法,以滿足不同的使用需求。例如,程式碼1-4是 CacheException類的一組構造方法,共包含四個輸入引數不同的方法。

【程式碼1-4】

在本文中,將使用 CacheException 來指代具有該方法名的上述四個方法,而使用CacheException()來特指方法一,使用 CacheException(String,Throwable)來特指方法三。

2.核心方法

在某些情況下,具有相同方法名的一組方法是為了便於外部呼叫而過載的,其核心實現邏輯都集中在某一個方法內,其他方法只做了轉接適配的工作。

例如,程式碼1-5所示的三個 selectMap方法中,方法一、二中僅僅進行了預設引數的設定、轉化等簡單的適配操作,然後呼叫了方法三。

方法三中則包含了核心的操作邏輯。

【程式碼1-5】

在本文中,將方法三這樣的包含核心操作邏輯的方法稱為核心方法。所以,selectMap (String,Object,String,RowBounds)就是selectMap這一組方法中的核心方法。

非核心方法中的程式碼大多十分簡單和易於理解,因此在後面的原始碼分析中,我們多圍繞核心方法展開。

9
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 深度學習系統中的實際Bug分類