bytebuddy的開發指南-翻譯


原文鏈接

翻譯這個的目的是,簡述了源碼的結構


入門

首先,您需要在本地計算機上創建Byte Buddy的副本。克隆存儲庫後,您可以使用Maven構建項目 。你的shell命令,這可能看起來像這樣:

git clone https://github.com/raphw/byte-buddy.git
cd byte-buddy
mvn package

在開始編碼之前,請確保所有測試用例都能成功運行。Byte Buddy的master分支一直都是這種情況。我們當前的Travis版本可以肯定地證實了這一點 ,該版本在監測Byte Buddy的最新狀態。Travis被設置爲針對Open JDKv6v7以及 Oracle JDKv6v7來編譯和測試項目 。由於我們某些測試是創建和加載Java類,因此要確保所生成類的格式能被特定Java版本能夠解析。如果您要對Byte Buddy進行更改並且會直接影響所生成的字節碼,請在提交更改之前確保使用不同的Java版本充分測試您的更改。這些都意味着您需要編寫與Java 6編譯器兼容的Java代碼。通常,您的代碼應至少具有90%的測試覆蓋率,但是與只嘗試碰到任何行的測試相比,我們推薦進行徹底(100%)的測試。您可以隨時運行Maven的cobertura:cobertura來獲取覆蓋率。Byte Buddy當前的測試覆蓋率是85%。作爲更現代的替代方法,Byte Buddy還支持通過從Maven 運行變異測試org.pitest:pitest-maven:mutationCoverage 。但是請記住,與計算覆蓋率相比,運行變異測試需要大量額外的運行時間。最後,可以激活Maven 的integration profile 配置文件,以掃描代碼庫中潛在的錯誤。這個配置文件是始終在持續集成服務器上激活的。 另一方面,checks profile聚集了運行速度更快的代碼檢查,並且對於任何Maven構建默認情況下都被激活。

該項目分爲不同的模塊。

  • 根項目byte-buddy-parent是任何Byte Buddy模塊配置的共同基礎。
  • 項目的實現代碼在byte-buddy-dev模塊。該模塊是直接依賴ASM庫,因此dev作爲模塊的名字。
  • 由於ASM庫·不能保證向後兼容性·,因此byte-buddy模塊負責將ASM依賴關係重新打包到Byte Buddy自己的名稱空間中。這樣做會將ASM依賴(shift)重命名爲net.bytebuddy.jar.asm。這個dependency-free無依賴的模塊沒有定義其自身的來源,而是依賴於byte-buddy-dev模塊。在其構建過程中,將解決所有依賴性並創建dependency-free部署描述符。更多的說明在如何定義對Byte Buddy的依賴關係的部分。爲了重新打包,您需要使用extras profile配置文件運行Maven構建,這將進一步觸發源代碼的構建和javadoc的生成。如果gpg Maven嘗試爲所有產出簽名。爲了實現這一點, 簽名者必須正確配置gpg插件。
  • 作爲另一個模塊,byte-buddy-benchmark包含一個 JMH基準測試,,用於測量Byte Buddy的運行時的耗時與性能,來和與其他代碼生成庫相比。
  • byte-buddy-agent該模塊提供了一個Java代理,該代理可以增強Byte Buddy的通用API。
  • byte-buddy-android模塊包含一個在Android平臺上起作用的ClassLoadingStrategy,其中 byte-buddy-android-test模塊定義了一個應用此策略的測試應用程序。這僅當android profile配置文件被激活時才構建它,因爲構建模塊需要Android SDK。

架構概覽

每個代碼生成框架都需要一種反映類型及其成員的方法。Byte Buddy通過TypeDescription接口訪問類型信息。該接口提供的API 和Java反射API 中定義的Class相似,並且可以使用TypeDescription.ForLoadedType來代表加載過的類,這個會包括具體的類型。但是,Byte Buddy也可以用於創建Java agent,在該Java agent中,需要在加載類之前對類進行操作。因此,Byte Buddy永遠不會對已經加載過的類型進行操作。所有描述類型接口都在net.bytebuddy.description包中找到。

同樣,Byte Buddy將泛型描述爲·ypeDescription.Generic接口的實例。該接口比Java自身的等效接口(TypeByte Buddy的Type接口,提供了用於處理各種通用類型的方法)豐富。當使用泛型的一些不支持的功能時將引發異常。我們選擇這種方法作爲Java語言所需的類型轉換方法更簡介的替代。由於大多數操作是由visitors(asm訪問字節碼的接口)執行的,因此實際上這並不是問題。

Byte Buddy建立在ASM字節代碼解析器之上,該解析器已成爲Java生態系統中字節代碼解析的事實上的標準。ASM的 接口來操作字節碼的生成,通常是使用代表名稱和描述符的字符串值來(所以很簡單)。Byte Buddy提供了一個StackManipulation 接口來封裝了visitors的命令,StackManipulation 用來和Byte Buddy 的 descriptio 接口交互,把需要的的值提取爲適當的格式並與ASM進行交互。此外,每種堆棧操作都知道其對JVM操作數堆棧大小的影響。這樣,就可以將幾種堆棧操作組合在一起,以計算它們對最小堆棧大小的共同要求。可以用一個ByteCodeAppender 來表示幾種堆棧操作的。字節碼追加器代表一個代碼塊,並且需要將操作數堆棧留空。另外,字節代碼追加器應該暴露爲本地變量(local variables 就是字節碼知識裏面的本地變量,)的空間(執行字節碼指令時,需要關聯使用這些變量)。通常,字節碼追加器由一個或多個堆棧操作組成。與代碼生成相關的所有類都收集在net.bytebuddy.implementation.bytecode包中。

每個字節碼附加器以接受方法的實現作爲入參,然後apply到目標方法上。此外,它還接收一個ASM visitor ,用於註冊該方法的代碼和的實例 Implementation.ContextImplementation.Context允許註冊輔助類型(auxiliary type)。輔助類型表示執行該方法所需的幫助程序類型(就是額外的工具類,以便於其他操作)。比如,一個代理類要調用被修改過的類中的方法。通常會使用MethodDelegation爲被修改過的類加一個@SuperCall註解。Implementation.Context是Byte Buddy中爲數不多的可變類之一,因爲它伴隨着的ASM 的method visitor 本事就是可變得(這裏的變是指動態生成,生成時依賴條件)。但是,由於Implementation.Context並未公開給公共API,因此也不應該由ByteCodeAppender 也不應該暴露Implementation.Context給用戶使用。

構造方法的top-level的API是Implementation接口。一個ByteCodeAppender,需要一個Implementation的是例給出一個instrumented type。此外,Implementation可以用來註冊額外的方法,字段或代碼塊,在instrumented type靜態初始化化的時候。最後,任何實現實例都會收到一個實例Implementation.Target,它提供了一種訪問instrumented type中屬性的方法,該屬性與具體的類型無關。例如,可以查詢instrumented typesuper方法 調用。如果用戶執行subclass的生成,則此查詢將返回真正super方法的。如果用戶進行type-rebasement,,則實現目標實現將調用被重新創建方法的原始代碼(原始代碼的方法被重命名,然後被放在新方法中)。

在Byte Buddy中,通過將屬性註冊到可以構造任何類型DynamicType.Builder。builder 本身構造了一個InstrumentedType實例,該實例可以擴展 TypeDescription以允許Byte Buddy的其他組件在創建其類型之前查看之前的的類型。此外,方法和字段實現以FieldRegistry或 方式註冊MethodRegistry。最後,動態類型構建器將所有收集的信息TypeWriter提供給與ASM API交互以生成類文件的所有類型,並將其應用於匹配的方法描述 。


編碼約定

Byte Buddy的目標是實現完全不變,除了與大多數易變的ASM庫進行交互的易變類之外。但是,可變組件必須隔離在與ASM交互的範圍內,並且不得暴露給最終用戶。此類實例也不應存儲爲字段的值。此外,某些組件(例如Byte Buddy的類加載器)由於其作爲類加載器的性質而可變。但是,應將Byte Buddy中的所有集合視爲不可變的,並且當從公共API返回集合時,也必須強制執行此屬性。

所有一成不變的類必須實現適當的hashCode,並equals爲對象平等是一些Byte Buddy組件的一個重要概念,方法。例如,任何Implementation實例都必須僅一次性準備instrumented type 類型,因爲在Java中兩次註冊具有相同名稱的字段是不合法的。爲確保這一點,Implementation將檢查任何對象是否與之前有機會準備插入類型的實現是否相等。如果實現內部依賴於不同的對象,則所有這些組件都必須履行其相等的約束,這一點很重要。另外,任何組件都應實施適當的 toString一種改進調試的方法,尤其是在幫助論壇上發佈了用戶的堆棧跟蹤信息時。使用ObjectPropertyAssertion,Byte Buddy可以運行單元測試來確定所有這些方法的正確實現。

Byte Buddy是強面向對象,但從面向函數設計上獲得了一些啓發。不幸的是,作爲許多其他庫開發人員使用的元庫,Byte Buddy受到強大的兼容性要求的約束,並在Java 6上進行編譯。爲模仿函數,Byte Buddy經常通過枚舉實現接口,其中枚舉產生命名函數。最後,類文件被用作相關類的容器而不是包。在類文件中,可以定義比top-level類更好的可見性範圍,例如通過允許protected只能由子類或在內部使用另一個類的類中看到的類。同樣,當重構後不再需要一個類時,此分組約定使刪除所有相關代碼變得容易。

作爲元庫,Byte Buddy試圖提供對API儘可能開放的API,因爲無法預期使用範圍。只要有可能,委託將是優於類擴展的首選擴展機制。所有代碼都應記錄在案,這使得此屬性 更易於通過自動檢查進行驗證。在Byte Buddy中,將其null用作字段,參數的值或方法返回值是一種不好的做法。模仿Java反射API的描述類型是一個例外,其中null值是常見的。由於描述實例(description instances)向最終用戶公開,因此決定將相似性視爲比一致性更重要的因素。所以潛在的null值必須記錄在方法上。對於Byte Buddy,未檢查的異常比檢查的異常更可取。


貢獻

修復錯誤後,只需 在GitHub上創建拉取請求即可。收到通知後,我們將盡快調查此事。但是,請確保已正確描述了更改和已解決的問題,並提供了一個可重現該問題並證明您的修復程序有效的測試用例。這使我們的工作更加輕鬆,我們將能夠更快地應用您的補丁。如果添加新的方法,字段或類型,請確保編寫一些描述其用途的代碼內文檔。如果您應用與性能相關的更改,請使用byte-buddy-benchmark套件。最後,請注意,Byte Buddy的新版本通常是在其自己的分支中開發的。

如果您要提供功能,請先聯繫我們,然後再花費大量時間,以便我們可以討論您的更改在Byte Buddy當前的開發狀態下如何有意義。字節夥伴旨在穩定地提供更多功能,但我們不會以其穩定性和代碼一致性爲代價來擴展其功能集。但是,不要因本公告而氣disc。如果您對Byte Buddy的源代碼有足夠的瞭解,能夠實現您想要共享的新功能,那麼您肯定會考慮一下,我們將盡最大努力將其合併到我們的版本中!只需與我們交談,我們非常樂意歡迎您加入我們。

如果您想爲Byte Buddy的文檔,本網頁上的描述甚至本網頁的結構和設計做出貢獻,絕對歡迎您這樣做!我們深信,透徹和最新的文檔是成功項目的關鍵,我們將盡最大努力實現這一信念。只要可以改善Byte Buddy的可訪問性或外觀,甚至可以進行很小的更改,因爲最終,該項目是爲用戶設計的。只需克隆此網頁,該網頁託管在項目gh-pages分支的GitHub上。該網頁是使用angular.js和 Twitter的Bootstrap創建的。

路線圖

Byte Buddy已達到1.0版,除了尚不支持的兩個功能外,還被認爲是功能完整。隨着1.0版的發佈,庫的穩定性和性能得到了極大的重視,並且防禦性地增加了新功能。自然,Java編程語言和字節代碼格式的發展將在未來需要較新的版本,而Byte Buddy的目標是提供一種向後兼容的方式來處理舊版本和較新版本的Java。Java 9支持目前仍處於試驗階段。從Java 8開始,Byte Buddy當前不支持以下功能:

類型推斷

Java編譯器可以推斷泛型類型。字節好友當前不提供此類功能。對類型推斷的支持將允許更好地驗證泛型類型並實現Assigner考慮泛型類型信息的。不幸的是,此功能在實際應用很少的情況下需要進行大量工作。因此,目前尚未實現。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章