【发布时间】:2021-05-18 13:50:07
【问题描述】:
是否可以在没有 Java 代理的情况下动态检测 Java 字节码?我之前使用 Java 代理对字节码进行了检测,做了类似的事情:
ClassFileTransformer myTransformer = new Transformer();
instrument.addTransformer(myTransformer, true);
instrument.retransformClasses(classInstance);
instrument.removeTransformer(myTransformer);
但是,如果不使用 Java 代理,这可能吗?我想做的是调用一个方法,该方法将在 JVM 运行后的任何给定时间执行我的检测,而无需使用代理。
【问题讨论】:
-
加载时间转换可以使用自定义类加载器完成,对于通过此加载器加载的类。重新定义或重新转换是不可能的。如果 JVM 支持,您可以稍后启动一个新代理,例如 this answer 的末尾,但是,HotSpot JVM 的最新版本需要在启动时启用自连接。您可以通过启动另一个执行附加的进程来规避此问题,但是您会看到,事情变得越来越复杂。
-
@Holger 我能否附加到不同的 JVM 并将
Instrumentation的实例从那个转移到我想重新转换的那个?我只是无法连接到我想直接检测的 JVM。 -
@Holger,如果我设法获得对
Instrumentation引擎的引用,为什么无法重新定义或重新转换?我一直都在这样做,通常使用net.bytebuddy:byte-buddy-agent(它特别不包含任何字节好友功能,只是有助于开始检测)来简化问题,以节省手动工作。无需启动另一个进程并远程附加。 -
@kriegaex 获得
Instrumentation实例的唯一方法是使用Java 代理。如果byte-buddy-agent不是代理,那还有什么?仅仅因为你忽略了这个库实际上在做什么,这些步骤并没有变得不必要。 From the author of ByteBuddy: “你需要在虚拟机启动时设置该属性,而不是在运行时设置,否则会被忽略。否则,请查看可以解决该限制的 byte-buddy-agent。” 所以它确实包含解决方法。 -
@JerryJone 你不需要转移任何东西。辅助进程在这里没有做太多。代理仍然在您自己的 JVM 中启动,这就是在 JVM 中启动代理的含义。所有子进程都在做,附加到您的原始 JVM 并告诉它启动代理。从那时起,其他一切都将以与自连接相同的方式工作。代理存根可以将
Instrumentation引用传递给您的应用程序,您可以在那里使用它。但正如 kriegaex 所暗示的,最小化的 byte-buddy-agent 可以为您做到这一点;你不需要自己实现它。
标签: bytecode instrumentation agent java-bytecode-asm