我希望有人能解释一下这个项目,因为我可能会弄错:
我正在阅读有关 Java Agent Instrumentation 的文章,它说代理可以在 VM 启动后启动。因此,如果我想动态替换某些类(而不会使应用程序崩溃),这就是我要使用 agent-main 的目的吗?或者我需要在这里做更多的事情吗?
我知道人们可能会问“您是在谈论 JRebel 吗”- 并不是真的,因为我想做一些简单的事情,而 JRebel 太过分了。
仪器文档 - Java docs for Instrumentation
我理解所有的检测覆盖,但我有点困惑如何在应用程序启动后使用 -agent
参数挂接此代理。
最佳答案
首先,您的代理类需要指定一个 agentmain
方法,例如:
public class MyAgent {
public static void agentmain(final String args, final Instrumentation inst) {
try {
System.out.println("Agent loaded.");
} catch (Exception e) {
// Catch and handle every exception as they would
// otherwise be ignored in an agentmain method
e.printStackTrace();
}
}
}
例如,编译它并将其打包到一个jar 文件中。如果您选择 jar 变体,则它必须在其 manifest 文件 (MANIFEST.MF)。它指向实现 agentmain
方法的类。它可能看起来像:
Manifest-Version: 1.0
Agent-Class: package1.package2.MyAgent
例如,如果它位于那些包中。
之后,您可以通过 VirtualMachine#loadAgent
方法 ( documentation ) 加载代理。请注意,这些类使用的机制是 Java 的Attach 库 的一部分。他们决定,因为大多数用户不需要它,所以不直接将它添加到系统路径中,但您可以直接添加它。它位于
pathToYourJDKInstallation\jre\bin\attach.dll
它需要位于系统属性 java.library.path
指向的地方。例如,您可以将它复制到您的 .../Windows/System32
文件夹或调整属性或类似的东西。
例如,如果您想在另一个当前运行的 jar 中注入(inject)一个 agent-jar,您可以使用如下方法:
public void injectJarIntoJar(final String processIdOfTargetJar,
final String pathToAgentJar, final String[] argumentsToPass) {
try {
final VirtualMachine vm = VirtualMachine.attach(processIdOfTargetJar);
vm.loadAgent(pathToAgentJar, argumentsToPass.toString());
vm.detach();
} catch (AttachNotSupportedException | AgentLoadException
| AgentInitializationException | IOException e) {
System.err.println("Unable to inject jar into target jar.");
}
}
使用相同的技术,您可以将 dll 库(如果它们通过 native 代理接口(interface)实现相应的代理方法)注入(inject) jar。
实际上,如果这对您有帮助,我前段时间已经为这类东西编写了一些小型库。参见 Mem-Eater-Bug ,对应的类是Injector.java整个项目有一个小Wiki .
它有一个示例,展示了如何使用该技术来操纵以 Java 应用程序编写的 SpaceInvaders 游戏。
关于java - VM 启动后启动 Instrumentation Agent,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45701826/