天天看点

bytebuddy的开发指南-翻译入门架构概览编码约定贡献路线图

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 JDK

v6

v7

以及 Oracle JDK

v6

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考虑泛型类型信息的。不幸的是,此功能在实际应用很少的情况下需要进行大量工作。因此,目前尚未实现。