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~