jvm 如何确定ASM Java插装是在编译时还是在运行时发生?

lhcgjxsq  于 6个月前  发布在  Java
关注(0)|答案(1)|浏览(66)

我对Java生态系统有点陌生。我正在阅读ASM方法(在这个文档https://www.baeldung.com/java-asm中)来做Java插装。
我不知道ASM什么时候改变字节码,具体来说,它在编译时生效,直接改变类,或者它在类加载的运行时改变代码。

im9ewurl

im9ewurl1#

ASM库根本不负责更改字节码。它是一个将字节序列(类文件格式)转换为另一个字节序列(同样是类文件格式)的工具,尽管您也可以使用它来分析类文件或从头开始生成类文件。
所以你在最后得到的,只是一个字节数组。
由于使用这个字节数组来有效地更改类(如果这是您想要的)是您自己的责任,因此您是决定如何以及何时应用更改的人。

  • 您可以在文件系统中读取和写入类文件,这就像从文件中阅读字节和向文件中写入字节一样微不足道。这些更改将在下次使用此位置作为类路径或模块路径启动JVM时生效。如果已经有一个JVM正在使用此位置运行,则更改可能在加载类时生效(如果尚未加载)。
  • 您可以在MethodHandles.Lookup上使用defineClass将类注入到现有的上下文中,该上下文将取代现有的类定义 (如果尚未加载)
  • 您可以使用更改的类定义创建自定义ClassLoader,从技术上讲,这不是更改类,而是在自己的上下文中创建新版本。这对于某些用例仍然可行。
  • 实际上,在运行时更改类可以通过代理或编译器完成。Java代理可以使用Instrumentation API,它允许安装类文件转换器,以便按需调用或主动触发转换。API允许加载时转换或更改已加载的类,但允许对已加载的类进行的更改是有限的。

重定义可以更改方法体、常量池和属性(除非明确禁止)。重定义不能添加、删除或重命名字段或方法,更改方法的签名,更改修饰符或更改继承。重定义不能更改NestHostNestMembersRecordPermittedSubclasses属性。

相关问题