你可以使用Javaassist以及任何其他字节码工程库来做到这一点。神奇之处在于Java Attach API,它允许程序附加到正在运行的JVM(并修改加载的类)。
它可以在com.sun.tools.attach
软件包中找到,顾名思义,它是特定于Oracle JVM的。尽管如此,JDK工具喜欢并使用它来支持他们的“附加到正在运行的JVM”功能,所以可以肯定地说它将继续存在。jstack
jmap
Attach API 上的文档具有相当的描述性,这篇 Oracle 博客文章演示了在运行时附加代理。一般来说,它归结为:
- 使重构程序以“常规”方式进行,使用等
-javaagent
premain
- 重命名为
premain
agentmain
- 创建一个临时 JAR 文件,其中包含您的代理类,并具有指向您的代理(包含)类的清单,并将其设置为
Agent-Class
agentmain
Can-Retransform-Classes
true
- 获取目标 JVM 的 PID(可能具有相同的进程),并将临时 jar 附加到该 JVM 上
值得庆幸的是,API可以在您不需要太多工作的情况下完成此操作,但是如果您在运行时进行JAR生成,那么打包代理所需的所有类可能会有点棘手。
我希望包含一个演示代理,演示在运行时附加探查器,但最终它太长而无法发布。尽管如此,我已经把它放在Github存储库中。
这种方法的一个警告是,它使您的程序依赖于随JDK一起提供的程序,并且JRE中不存在。您可以通过随应用程序一起交付(或提取)来解决此问题,但您仍然需要随应用程序一起提供 Attach API 所需的本机库。我已经包含了我在上面链接的存储库中可以找到的所有平台的库,尽管您也可以自己获取它们。tools.jar
tools.jar
attach
根据您的使用案例,这可能是也可能不理想。但它肯定有效!
这在问题中并不清楚,但是如果您希望做的是在运行时用您自己的类完全“热插拔”,则不需要使用任何字节码操作库。相反,您可以单独编译类(确保相同的包、类名等),并在目标类上调用时简单地返回新类的字节。transform