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