Instrumentation 两种方法 premain Agent

由于jvm内部的限制Instrumentation 只能修改方法体 不能动态添加删除方法(安全第一吧!!!!)

Premain

对于使用命令行接口的实现,可以将以下选项添加到命令行来启动代理:

-javaagent:jarpath[=options]

jarpath 是代理 JAR 文件的路径。 options 是代理选项。此开关可以在同一代码行使用多次,从而创建多个代理。多个代理可以使用相同的 jarpath。代理 JAR 文件必须遵守 JAR 文件规范。

代理 JAR 文件的清单必须包含 Premain-Class 属性。此属性的值是代理类 的名称。代理类必须实现公共静态premain 方法,该方法的原理与 main 应用程序入口点类似。在 Java 虚拟机 (JVM) 初始化后,每个 premain 方法将按照指定代理的顺序调用,然后将调用实际的应用程序 main 方法。每个 premain 方法必须按照依次进行的启动顺序返回。

premain 方法有两种可能的签名。JVM 首先尝试在代理类上调用以下方法:

public static void premain(String agentArgs, Instrumentation inst);

如果代理类没有实现此方法,那么 JVM 将尝试调用:

public static void premain(String agentArgs);

如果代理在 VM 启动之后启动,那么代理类还有一个要使用的 agentmain 方法。如果是使用命令行选项启动代理,那么 agentmain 方法将不会被调用。

代理类将被系统类加载器加载(参见 ClassLoader.getSystemClassLoader)。系统类加载器是通常加载包含应用程序 main 方法的类的类加载器。 premain 方法将在与应用程序 main 方法相同的安全性和类加载器规则下运行。不存在代理 premain 方法可以执行的建模限制。任何应用程序 main 可以执行的事情(包括创建线程)对于 premain 都是合法的。

每个代理通过 agentArgs 参数传递其代理选项。代理选项作为单个字符串传递,任何其他解析应由代理本身执行。

如果该代理不能被解析(例如,由于无法加载代理类,或者代理类没有恰当的 premain 方法),那么 JVM 将中止。如果 premain 方法抛出未捕获的异常,那么 JVM 将中止。

简单点说 就是要在JVM 启动 通过 -javaagent 启动这个程序才有效

VM 启动后启动代理

实现可以提供一种机制在 VM 启动之后某一时刻启动代理。如何初启的细节是特定于实现的,但通常应用程序已经启动并且其 main 方法已经调用。如果实现支持在 VM 启动之后启动代理,则以下内容适用:

  1. 代理 JAR 的清单必须包含属性 Agent-Class。此属性的值是代理类 的名称。

  2. 代理类必须实现公共静态 agentmain 方法。

  3. 系统类加载器(ClassLoader.getSystemClassLoader)必须支持将代理 JAR 文件添加到系统类路径的机制。

代理 JAR 将被添加到系统类路径。系统类路径是通常加载包含应用程序 main 方法的类的类路径。代理类将被加载,JVM 尝试调用 agentmain 方法。JVM 首先尝试对代理类调用以下方法:

public static void agentmain(String agentArgs, Instrumentation inst);

如果代理类没有实现此方法,那么 JVM 将尝试调用:

public static void agentmain(String agentArgs);

如果代理是使用命令行选项启动的,那么代理类还有一个要使用的 agentmain 方法。如果是在 VM 启动之后启动代理,那么 agentmain 方法将不会被调用。

代理通过 agentArgs 参数传递其代理选项。代理选项作为单个字符串传递,任何其它解析应该由代理本身执行。

agentmain 方法应该执行任何启动代理所需的初始化。启动完成时该方法应返回。如果代理无法启动(例如,由于无法加载代理类,或者代理类没有构造 agentmain 方法),那么 JVM 将中止。如果 agentmain 方法抛出未捕获的异常,那么它将被忽略。

这种情况就是在你根本就不知道  premain的时候 用 agentmain 也能达到目的。

如果  java.lang.UnsatisfiedLinkError: no attach in java.library.path

 System.setProperty("java.library.path","D:\Program Files (x86)\Java\jdk1.6.0_21\jre\bin");
 Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
 fieldSysPath.setAccessible(true);
 fieldSysPath.set(null, null);

new AttachThread("D:\bainiangzi\Agent\Agent_fat.jar", VirtualMachine.list()).start();

vm = VirtualMachine.attach(listBefore.get(0));

vm.loadAgent(jar);
vm.detach();

原文地址:https://www.cnblogs.com/beautiful-code/p/6424925.html