Java 无需外部库的字节码操作
Java Bytecode Manipulation Without External Library
ASM、BCEL、Javaassist 和 AspectJ 等库都能够进行运行时字节码操作,但它们是如何实现的?
我以前使用 ASM 做过一些基本的字节码操作,但我不明白它是如何工作的。 Java Agent 是否在程序的其余部分之前在 JVM 中执行,允许 ASM 加载已编译的 classes 并在它们被 JVM 执行之前编辑它们?
如果是这样,是否可以执行 java 字节码操作而不使用外部库(如 ASM)并使用 BufferedReader 加载编译的 class 文件并编写自定义解析器等?
Class 文件只是一个字节序列,其格式在 The Java Virtual Machine Specification 中指定。 BufferedReader
用于文本文件,因此您需要 BufferedInputStream
,但格式非常复杂。
您可以加载操纵的 class 文件,就好像它们是由 javac
生成的一样。您还可以使用 java.net.URLClassLoader.newInstance
或类似的方式动态加载它们。 Java 代理允许在加载文件时修改 class 文件,通过 Java 或本机界面(如果您想修改 classes 是必需的在加载 classes 的 classes 之前加载。
这些库采用标准 Java API,当然,您也可以在没有这些库的情况下自行使用。
首先,Java class 文件只是格式明确的字节序列,如 JVMS §4, The class File Format 中所指定。上述库的主要任务是提供用于处理这种格式的字节序列的工具。第二个是关于获取现有或导出修改或新建的定义 classes.
第二个任务有两种不同的处理方式。一种是从持久存储(如文件系统或 jar 文件等)中读取已编译的 classes,并将它们写回这些存储,而特定代码不是 运行,就像构建和部署工具那样。这应该是微不足道的,因为它归结为读取和写入字节。
另一种是在运行时操纵 classes,这可以由 Java 代理通过 Instrumentation API 完成。它提供了在首次使用前 loading/definition 时间拦截 classes 的机制,而且还重新定义了 classes。后者不能随意更改,目前必须保留所有字段和方法的声明,所以主要用于更改方法的可执行代码。
如果您想要 class 文件处理示例而不需要额外的第 3 方库,Whosebug 上有一些答案
- Extract the class name from a class file
- Find all class dependencies
当然,这些示例只是单一用途的代码或草图。如果您将它们扩展为更通用或更有用的东西,您很快就会基本上重新实现这些库。
ASM、BCEL、Javaassist 和 AspectJ 等库都能够进行运行时字节码操作,但它们是如何实现的?
我以前使用 ASM 做过一些基本的字节码操作,但我不明白它是如何工作的。 Java Agent 是否在程序的其余部分之前在 JVM 中执行,允许 ASM 加载已编译的 classes 并在它们被 JVM 执行之前编辑它们?
如果是这样,是否可以执行 java 字节码操作而不使用外部库(如 ASM)并使用 BufferedReader 加载编译的 class 文件并编写自定义解析器等?
Class 文件只是一个字节序列,其格式在 The Java Virtual Machine Specification 中指定。 BufferedReader
用于文本文件,因此您需要 BufferedInputStream
,但格式非常复杂。
您可以加载操纵的 class 文件,就好像它们是由 javac
生成的一样。您还可以使用 java.net.URLClassLoader.newInstance
或类似的方式动态加载它们。 Java 代理允许在加载文件时修改 class 文件,通过 Java 或本机界面(如果您想修改 classes 是必需的在加载 classes 的 classes 之前加载。
这些库采用标准 Java API,当然,您也可以在没有这些库的情况下自行使用。
首先,Java class 文件只是格式明确的字节序列,如 JVMS §4, The class File Format 中所指定。上述库的主要任务是提供用于处理这种格式的字节序列的工具。第二个是关于获取现有或导出修改或新建的定义 classes.
第二个任务有两种不同的处理方式。一种是从持久存储(如文件系统或 jar 文件等)中读取已编译的 classes,并将它们写回这些存储,而特定代码不是 运行,就像构建和部署工具那样。这应该是微不足道的,因为它归结为读取和写入字节。
另一种是在运行时操纵 classes,这可以由 Java 代理通过 Instrumentation API 完成。它提供了在首次使用前 loading/definition 时间拦截 classes 的机制,而且还重新定义了 classes。后者不能随意更改,目前必须保留所有字段和方法的声明,所以主要用于更改方法的可执行代码。
如果您想要 class 文件处理示例而不需要额外的第 3 方库,Whosebug 上有一些答案
- Extract the class name from a class file
- Find all class dependencies
当然,这些示例只是单一用途的代码或草图。如果您将它们扩展为更通用或更有用的东西,您很快就会基本上重新实现这些库。