原文鏈接
翻譯這個的目的是,簡述了源碼的結構
入門
首先,您需要在本地計算機上創建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 JDKv6
和 v7
以及 Oracle JDKv6
和 v7
來編譯和測試項目 。由於我們某些測試是創建和加載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.Context
。Implementation.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 type
的 super方法 調用。如果用戶執行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考慮泛型類型信息的。不幸的是,此功能在實際應用很少的情況下需要進行大量工作。因此,目前尚未實現。