使用 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 at\t" + new Date());
}
return null;
}
}
怎么能够打成jar包?
首先在classpath 下增加一个 resources\META-INF\MANIFEST.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~
https://mp.weixin.qq.com/s/GU8-8_EhnAmvYuq_k98D_Q