由于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 启动之后启动代理,则以下内容适用:
-
代理 JAR 的清单必须包含属性
Agent-Class
。此属性的值是代理类 的名称。 -
代理类必须实现公共静态
agentmain
方法。 -
系统类加载器(
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();