是否可以在虚拟机从同一 VM 内启动后插入 javaagent?
例如,我们在 jar myagent.jar 中有一个代理,它具有适当的元数据设置和一个已经实现的 agentmain 方法。现在用户程序调用一个 API 调用,这应该会导致代理的插入,以便它可以重新定义类。
可以做到吗?怎么做?
是否可以在虚拟机从同一 VM 内启动后插入 javaagent?
例如,我们在 jar myagent.jar 中有一个代理,它具有适当的元数据设置和一个已经实现的 agentmain 方法。现在用户程序调用一个 API 调用,这应该会导致代理的插入,以便它可以重新定义类。
可以做到吗?怎么做?
https://web.archive.org/web/20141014195801/http://dhruba.name/2010/02/07/creation-dynamic-loading-and-instrumentation-with-javaagents/有一个很好的例子来说明如何编写代理以及如何即时启动代理。
是的,您只需将 JVM 进程 ID 传递给该VirtualMachine.attach(String pid)
方法,然后加载代理 jar。该类VirtualMachine
在 JDK_HOME/lib/tools.jar 文件中可用。这是我如何在运行时激活代理的示例:
public static void attachGivenAgentToThisVM(String pathToAgentJar) {
try {
String nameOfRunningVM = ManagementFactory.getRuntimeMXBean().getName();
String pid = nameOfRunningVM.substring(0, nameOfRunningVM.indexOf('@'));
VirtualMachine vm = VirtualMachine.attach(pid);
vm.loadAgent(pathToAgentJar, "");
vm.detach();
} catch (Exception e) {
e.printStackTrace();
}
}
您应该能够在 Java 6 中执行此操作,请参阅包文档章节“在 VM 启动后启动代理”
编辑:也许在 Java 5 中已经有可能了,只是 javadocs 没有明确提到它
遇到同样的问题后,我从 ByteBuddy 库中找到了更全面的解决方案。
ByteBuddy 彻底尝试动态加载其 java 代理:
在当前运行的 Java 虚拟机上安装代理。不幸的是,这并不总是有效。支持 Java 代理的运行时安装:
JVM 版本 9+:对于至少版本 9 的 Java VM,附件 API 已移动到一个模块中,如果 {@code jdk.attach} 模块可用于 Byte Buddy,则可以进行运行时安装,该模块通常仅适用于 VM附带 JDK。 OpenJDK / Oracle JDK / IBM J9 版本 8-:HotSpot 的安装只有在与 JDK 捆绑时才可能,并且需要与 VM 捆绑的 {@code tools.jar},这通常仅适用于 JVM 的 JDK 版本。 在运行 Linux 并包含可选的junixsocket-native-common依赖项时,Byte Buddy 模拟 Unix 套接字连接以附加到目标 VM。