诸如ASM,BCEL,Javaassist和AspectJ之类的库都具有运行时字节码操纵的能力,但是它们如何实现这一点?
我之前使用ASM做过一些基本的字节码操作,但是我不知道它是如何工作的。 Java代理是否在程序的其余部分之前在JVM中执行,是否允许ASM加载已编译的类并在JVM执行它们之前对其进行编辑?
如果是这样,是否可以在不使用ASM之类的外部库的情况下执行Java字节码操作,并使用BufferedReader加载已编译的类文件并编写自定义解析器等?
答案 0 :(得分:1)
类文件只是字节序列,其格式在The Java Virtual Machine Specification中指定。 BufferedReader
用于文本文件,因此您希望使用BufferedInputStream
,但是格式非常复杂。
您可以加载受操纵的类文件,就像它们是由javac
生成的一样。您也可以使用java.net.URLClassLoader.newInstance
或类似名称动态加载它们。 Java代理允许在加载类文件时通过Java或本机接口进行修改(如果要修改在加载类之前加载的类,则后者是必需的)。
答案 1 :(得分:1)
这些库基于标准Java API,当然,您也可以在没有这些库的情况下使用自己。
首先,Java类文件只是JVMS §4, The class File Format中指定的格式明确的字节序列。提到的库的主要任务是提供用于处理这种格式的字节序列的工具。第二个是获取现有或导出已修改或新创建的类的定义。
处理第二个任务有两种不同的方式。一种是从持久性存储(例如文件系统或jar文件等)中读取已编译的类,然后在特定代码未运行时将它们写回到这些存储中,例如构建和部署工具。这应该很简单,因为它可以归结为读写字节。
另一种方法是在运行时操作类,这可以由Java代理通过Instrumentation API完成。它提供了在加载/定义第一次使用类之前拦截类的机制,还提供了重新定义类的机制。后者不能自由更改它们,目前,它必须保留所有字段和方法声明,因此它主要可用于更改方法的可执行代码。
如果您想在没有其他第三方库的情况下进行类文件处理的示例,请在Stackoverflow上找到一些答案
当然,这些示例仅是单一用途的代码或草图。如果将它们扩展到更通用或更有用的功能,很快您将最终基本上重新实现这些库。