是否可以在虚拟机启动后从同一个VM中插入javaagent?
让我们说例如我们在jar myagent.jar中有一个代理,它具有相应的元数据设置和已经实现的agentmain方法。现在,用户程序调用API调用,这将导致代理插入,以便它可以重新定义类。
能做到吗?怎么做?
答案 0 :(得分:20)
https://web.archive.org/web/20141014195801/http://dhruba.name/2010/02/07/creation-dynamic-loading-and-instrumentation-with-javaagents/有一个很好的例子,说明如何编写代理以及如何动态启动代理。
答案 1 :(得分:14)
是的,您只需将JVM进程ID传递给VirtualMachine.attach(String pid)
方法,然后加载代理jar。 JDK_HOME / lib / tools.jar文件中提供了VirtualMachine
类。以下是我在运行时如何激活代理的示例:
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();
}
}
答案 2 :(得分:4)
您应该可以在Java 6中执行此操作,请参阅package documentation章节“VM启动后启动代理”
编辑:也许在Java 5中已经可以了,只是javadocs没有明确提到它
答案 3 :(得分:0)
遇到相同的问题,我发现了一个更加全面的解决方案from the ByteBuddy library。
ByteBuddy彻底尝试动态加载其Java代理:
在当前运行的Java虚拟机上安装代理。不幸的是,这并不总是有效。 Java代理的运行时安装受以下支持:
JVM版本9 + :对于版本至少为9的Java VM,附件API已移至模块中,并且如果{@code jdk.attach}模块可用,则可以进行运行时安装到Byte Buddy,通常仅适用于JDK附带的VM。 OpenJDK / Oracle JDK / IBM J9版本8-:仅当与JDK捆绑在一起时才可以安装HotSpot,并且需要与VM捆绑在一起的{@code tools.jar}仅适用于JVM的JDK版本。 运行Linux并包括可选的 junixsocket-native-common 依赖项时,Byte Buddy仿真Unix套接字连接以附加到目标VM。