premain 是 Java SE5 开始就提供的代理方式, 由于其必须在命令行指定代理 jar, 并且代理类必须在 main 方法前启动. 因此, 要求开发者在应用前就必须确认代理的处理逻辑和参数内容等等. 在有些场合下, premain 代理方式不能满足需求. 为解决运行时启动代理类的问题, Java SE6 开始提供了在应用程序的 VM 启动后在动态添加代理的方式, 即 agentmain 方式.
在 manifest 中指定 Agent-Class 属性, 值为代理类全路径
代理类需要提供 public static void agentmain(String args, Instrumentation inst) 或 public static void agentmain(String args) 方法. 并且再二者同时存在时以前者优先. args 和 inst 和 premain 中的一致.
- package aty.agent.after;
- import java.lang.instrument.Instrumentation;
- public class AgentAfterMain{
- public static void agentmain(String args, Instrumentation inst){
- System.out.println("loadagent after main run.args=" + args);
- Class<?>[] classes = inst.getAllLoadedClasses();
- for (Class<?> cls : classes){
- System.out.println(cls.getName());
- }
- System.out.println("agent run completely.");
- }
- }
将该代理类打成 jar 包, 并修改 MANIFEST.MF 文件
- Manifest-Version: 1.0
- Agent-Class: aty.agent.after.AgentAfterMain
编写好 agent jar 之后, 接下来需要将该 jar 挂接到目标进程的 jvm 中执行. 由于 agent main 方式无法向 pre main 方式那样在命令行指定代理 jar, 因此需要借助 Attach Tools API. 使用 com.sun.tools.attach 包下的 VirtualMachine 类, 使用 attach pid 来得到相应的 VirtumalMachine, 使用 loadAgent 方法指定 AgentMain 所在类并加载. 其中 com.sun.tools.attach.VirtualMachine 的 jar 包是 jdk 下 lib 中的 tools.jar
- package aty.agent.after;
- import com.sun.tools.attach.VirtualMachine;
- public class RunAttach{
- public static void main(String[] args) throws Exception{
- // args[0] 传入的是某个 jvm 进程的 pid
- String targetPid = args[0];
- VirtualMachine vm = VirtualMachine.attach(targetPid);
- vm.loadAgent("F:/workspaces/j2se 练习代码 / jvm_high_api/agentmain.jar","toagent");
- }
- }
来源: http://www.bubuko.com/infodetail-3462136.html