Instrumentation 介紹與使用
- 2019 年 10 月 6 日
- 筆記
使用 Insrumentation ,開發者而言構建一個獨立於應用程式的代理程式(Agent),監測和協助運行在JVM 上的程式,甚至可以替換和修改某些類的定義。簡單的來說 開發者使用Instrumentation 可以實現一種虛擬機級別的AOP實現。
Instrumentation 的最大作用,就是類定義動態改變和操作。程式運行時,通過 -javaagent 參數指定一個特定的 jar 文件來啟動 Instrumentation 的代理程式。其實這個對很多人來說不陌生 xmind, idea 永久破解的過程中,都有使用 -javaaegent ,然後指定一個 jar 文件。甚至一些監控軟體也用了,例如 skywalking。
看看怎麼用
java.lang.instrument 包的具體實現。
代理類
import java.lang.instrument.Instrumentation; public class Agent { /** * 編寫一個 Java 類 包含 * public static void premain(String agentArgs, Instrumentation inst); [1] * public static void premain(String agentArgs); [2] * @param options * @param ins */ public static void premain(String options, Instrumentation ins) { if (options != null) { System.out.printf(" I've been called with options: "%s"n", options); } else { System.out.println(" I've been called with no options."); } ins.addTransformer(new Transformer()); } }
transformer 類
import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; import java.security.ProtectionDomain; import java.util.Date; public class Transformer implements ClassFileTransformer { @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { if ("com/wangxiaoming/instrument/Dog".equals(className)) { System.out.println("Dog's method invoke att" + new Date()); } return null; } }
怎麼能夠打成jar包?
首先在classpath 下增加一個 resourcesMETA-INFMANIFEST.MF 文件
Manifest-Version: 1.0 Premain-Class: com.wangxiaoming.instrument.Agent Can-Redefine-Classes: true
關鍵在 Permain-Class :對應的類路徑得和真實的一致。
其次是 maven pom.xml 中
<build> <finalName>agent</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>2.3.1</version> <configuration> <archive> <manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile> </archive> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.18.1</version> <configuration> <skipTests>true</skipTests> </configuration> </plugin> <plugin> <artifactId>maven-assembly-plugin</artifactId> <configuration> <outputDirectory>${basedir}</outputDirectory> <archive> <index>true</index> <manifest> <addClasspath>true</addClasspath> </manifest> <manifestEntries> <Premain-Class>com.wangxiaoming.instrument.Agent</Premain-Class> </manifestEntries> </archive> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build>
然後 mvn install 即可 生成 一個 agent.jar
測試一下
public class InstrumentTest { public static void main(String[] args) { System.out.println(new Dog().hello()); } }
public class Dog { public String hello() { return "wow wow~"; } }
java -javaagent:jar 文件的位置 [= 傳入 premain 的參數 ]

運行結果
I've been called with options: "hello" Dog's method invoke at Sun Sep 22 23:01:52 CST 2019 wow wow~