字节码 manipulation/enhancement 和 Java 检测 API
Bytecode manipulation/enhancement and Java Instrumentation API
我很难理解字节码 manipulation/enhancement 和 Java 检测 API 之间的依赖关系。
根据我对任何字节码的理解manipulation/enhancement我们有两个选择
- 构建时 - Java 类 被编译为
*.class
然后是其他一些
library/application 应该被执行以进行操作。
- 加载时间 - 仅通过制作
使用 Java 工具 API,这意味着特定的
必须提供javaagent。
我不确定的事情:
是否有构建时字节码操作之类的东西,有哪些 frameworks/libs 支持它(例如 Javassist,ASM)他们使用一些通用方法还是只是读取和解析字节码,然后为您提供修改它的方法?
加载时操作是否仅依赖于 Java 检测 API?意味着所有可用的 frameworks/libs(例如 Javassist、ASM)都使用 javaagent 来进行操作?
请注意,我对这个主题的经验很少,所以我有可能误解或遗漏了一些概念。我试图将这个复杂的主题归结为一些简单的解释,即使它非常笼统或使用类比进行演示。
将已编译的 Java class 文件视为包含特定 Java class 的任何信息的 byte[]
数组。此上下文中的检测指的是 post 的过程 - 将此字节数组处理成不同的形状,与何时或如何发生无关。可以在编译和 class 加载之间的任何时间应用检测;在 Java 中,一个 class 甚至可以 be instrumented after it has been loaded 不改变其形状的限制,即 adding/removing 字段或方法。但无论何时应用检测,概念都保持不变,即重新排列表示已编译的字节数组 Java class.
我所知道的任何字节码操作库都允许处理来自任何来源的 class 文件。通常,这些库的最通用输入是一个简单的字节数组,为方便起见,可以选择从 class 加载程序加载它。可以通过 ClassLoader.getResourceAsStream
方法以 class 文件的名称作为参数从 class 加载程序中查找 class 文件。例如:
classLoader.getResourceAsStream("some/Sample.class")
应该解析 class 文件以获得虚构的 some.Sample
class。这通常是因为 class 文件(字节数组)需要由 class 加载程序定位,以便在首次请求时加载 class。
在构建时,class 文件通常位于特定文件夹中,例如在 Maven 构建的 target/classes 文件夹中。要检测那些 classes,您只需要找到那些文件,将它们读入字节数组,然后写回更改后的结果。例如,您可以通过编写自己的 Maven 插件来做到这一点,例如您可以在其中使用 ASM 来调整文件。然而,为了方便起见,您也可以使用更高级的库,例如 Byte Buddy's Maven plugin into which you can load your own plugin 并完全避免 Maven 插件 API 甚至字节码 APIs。 (求助,本人是字节好友作者。)
在运行时,你可以做同样的事情,即找到位于某个文件夹或 jar 文件中的 class 文件,找到这些 classes 并在它们被应用程序加载之前调整它们。然而,这并不总是有效,因为 jar 文件也可能被其他也会受到影响的应用程序使用。此外,它会要求您的用户从他们的应用程序中明确激活此工具。因此,class 文件检测通常使用 Java 代理来应用,它可以访问 Instrumentation
API,这使得这更加方便。 API 允许在 Java 的内部 class 加载机制中安装一个挂钩,这样就可以在 class 的字节数组加载之前调整它:
instrumentation.addClassFileTransformer(
(Module module, ClassLoader loader, String name,
Class<?> classIfLoaded, ProtectionDomain pd, byte[] classFile) -> {
byte[] transformed = doSomethingWith(classFile);
return transformed;
});
此更改随后与应用程序隔离,不会更改原始 class 文件。检测 API 并不意味着使用任何库来修改 class 文件,这完全取决于您,每个人都在使用某种库甚至直接操作字节数组。诸如 Byte Buddy 之类的高级库甚至不需要您实现自己的 class 文件转换器,而是通过 AgentBuilder
API 拥有自己的抽象,但是它确实创建了 class 文件转换器在幕后使用仪器 API 的独特功能。其他库,如 ASM 或 Javassist 与 Instrumentation
API 没有任何关系,但是需要您实现自己的 class 文件转换器,您可以在其中使用 API 个库来处理所呈现的 class 文件。
我很难理解字节码 manipulation/enhancement 和 Java 检测 API 之间的依赖关系。
根据我对任何字节码的理解manipulation/enhancement我们有两个选择
- 构建时 - Java 类 被编译为
*.class
然后是其他一些 library/application 应该被执行以进行操作。 - 加载时间 - 仅通过制作 使用 Java 工具 API,这意味着特定的 必须提供javaagent。
我不确定的事情:
是否有构建时字节码操作之类的东西,有哪些 frameworks/libs 支持它(例如 Javassist,ASM)他们使用一些通用方法还是只是读取和解析字节码,然后为您提供修改它的方法?
加载时操作是否仅依赖于 Java 检测 API?意味着所有可用的 frameworks/libs(例如 Javassist、ASM)都使用 javaagent 来进行操作?
请注意,我对这个主题的经验很少,所以我有可能误解或遗漏了一些概念。我试图将这个复杂的主题归结为一些简单的解释,即使它非常笼统或使用类比进行演示。
将已编译的 Java class 文件视为包含特定 Java class 的任何信息的 byte[]
数组。此上下文中的检测指的是 post 的过程 - 将此字节数组处理成不同的形状,与何时或如何发生无关。可以在编译和 class 加载之间的任何时间应用检测;在 Java 中,一个 class 甚至可以 be instrumented after it has been loaded 不改变其形状的限制,即 adding/removing 字段或方法。但无论何时应用检测,概念都保持不变,即重新排列表示已编译的字节数组 Java class.
我所知道的任何字节码操作库都允许处理来自任何来源的 class 文件。通常,这些库的最通用输入是一个简单的字节数组,为方便起见,可以选择从 class 加载程序加载它。可以通过 ClassLoader.getResourceAsStream
方法以 class 文件的名称作为参数从 class 加载程序中查找 class 文件。例如:
classLoader.getResourceAsStream("some/Sample.class")
应该解析 class 文件以获得虚构的 some.Sample
class。这通常是因为 class 文件(字节数组)需要由 class 加载程序定位,以便在首次请求时加载 class。
在构建时,class 文件通常位于特定文件夹中,例如在 Maven 构建的 target/classes 文件夹中。要检测那些 classes,您只需要找到那些文件,将它们读入字节数组,然后写回更改后的结果。例如,您可以通过编写自己的 Maven 插件来做到这一点,例如您可以在其中使用 ASM 来调整文件。然而,为了方便起见,您也可以使用更高级的库,例如 Byte Buddy's Maven plugin into which you can load your own plugin 并完全避免 Maven 插件 API 甚至字节码 APIs。 (求助,本人是字节好友作者。)
在运行时,你可以做同样的事情,即找到位于某个文件夹或 jar 文件中的 class 文件,找到这些 classes 并在它们被应用程序加载之前调整它们。然而,这并不总是有效,因为 jar 文件也可能被其他也会受到影响的应用程序使用。此外,它会要求您的用户从他们的应用程序中明确激活此工具。因此,class 文件检测通常使用 Java 代理来应用,它可以访问 Instrumentation
API,这使得这更加方便。 API 允许在 Java 的内部 class 加载机制中安装一个挂钩,这样就可以在 class 的字节数组加载之前调整它:
instrumentation.addClassFileTransformer(
(Module module, ClassLoader loader, String name,
Class<?> classIfLoaded, ProtectionDomain pd, byte[] classFile) -> {
byte[] transformed = doSomethingWith(classFile);
return transformed;
});
此更改随后与应用程序隔离,不会更改原始 class 文件。检测 API 并不意味着使用任何库来修改 class 文件,这完全取决于您,每个人都在使用某种库甚至直接操作字节数组。诸如 Byte Buddy 之类的高级库甚至不需要您实现自己的 class 文件转换器,而是通过 AgentBuilder
API 拥有自己的抽象,但是它确实创建了 class 文件转换器在幕后使用仪器 API 的独特功能。其他库,如 ASM 或 Javassist 与 Instrumentation
API 没有任何关系,但是需要您实现自己的 class 文件转换器,您可以在其中使用 API 个库来处理所呈现的 class 文件。