Instrumentation包的简介
JDK从1.5开始,在rt.jar包下有了java.lang.instrument这个文件夹,刚开始只支持agent方式启动,但使用还是不太方便,因为我们在JDK1.6后增加了attach方式。在官方文档提供了两种方式
agent命令方式
在jvm启动参数中增加
-javaagent:jarpath[=options]
agent有两点要求:
- agent jar必须包含Premain-Class属性,值是agent class启动类
- 必须实现 一个 public static premain的方法
- JDK加载这个方法使用系统类加载器( ClassLoader.getSystemClassLoader),这个premain方法在同样的security和 classloader 规则下,也就是说应用程序能做的事情,这里都可以做,如创建线程等(这里意味着agent与运行程序共享同一个jvm)。
public static void premain(String agentArgs, Instrumentation inst);
public static void premain(String agentArgs);
这里注意JVM默认会先调用上面那个参数全的方法,没有实现该方法才会调用下面那个简略版方法
运行过程中attach方式
- agent JAR必须包含Agent-Class属性,值是agent class的启动类。
- 必须实现 public static agentmain 方法
- 系统类加载器(ClassLoader.getSystemClassLoader)必须支持加载agent jar到系统class路径下(可以设置参数关闭)
public static void agentmain(String agentArgs, Instrumentation inst);
public static void agentmain(String agentArgs);
同上面agent方式,也会优先调用参数全的那个方法
- agent jar支持的属性有
- Premain-Class :agent命令启动参数,类须实现premain方法
- Agent-Class :jvm启动后加载,类需实现agentmain方法
- Boot-Class-Path:启动类加载器加载的路径
- Can-Redefine-Classes:是否可以重新定义类,默认false
- Can-Retransform-Classes:是否可以变形类,默认false
- Can-Set-Native-Method-Prefix:是否设置内部方法前缀,默认false
agent打包插件
上面agent的这些属性,我们在打包时候如何设置呢,这里以maven-assembly-plugin插件为例,我们在assembly插件官网看到使用说明(http://maven.apache.org/plugins/maven-assembly-plugin/usage.html)
可以使用archive属性指定
<project>
[...]
<build>
[...]
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.3.0</version>
<configuration>
[...]
<archive>
<manifest>
<mainClass>org.sample.App</mainClass>
</manifest>
</archive>
</configuration>
[...]
</plugin>
[...]
</project>
这样打包后,我们在META-INF/MANIFEST.MF文件中写入值
[...]
Main-Class: org.sample.App
如果自己编写的模块如jvm-sanbox既支持agent方式又要支持attach方式,那么我们可以这么来写
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>attached</goal>
</goals>
<phase>package</phase>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifestEntries>
<Premain-Class>com.xxxx</Premain-Class>
<Agent-Class>com.xxx</Agent-Class>
<Can-Redefine-Classes>true</Can-Redefine-Classes>
<Can-Retransform-Classes>true</Can-Retransform-Classes>
</manifestEntries>
</archive>
</configuration>
</execution>
</executions>
</plugin>
参考文档:
官方文档:https://docs.oracle.com/javase/8/docs/api/index.html