JavaAgent 又称 Java 探针,是在 JDK5 引进的一种动态修改字节码的技术。它在 JVM 在加载字节码之前,获取字节码信息 通过字节码转换器修改字节码来实现一些额外的功能。JavaAgent本质可以理解成一个Jar包插件,使用 JVMTI(JVM Tool Interface)完成加载,利用 JVM 提供的 Instrumentatiion
接口来实现字节码加载前、加载后的修改。-javaagent 参数来指定一个 agent jar包,实现启动jvm时加载 agent。利用这一特性可以实现虚拟机级别的 AOP ,实时监控、分析虚拟机,干预虚拟机的执行。
Instrumentation(核心)JDK 官方提供
提供了注入字节码转换器的入口
字节码转换器接口,想要对字节码的转换需要实现该接口
Java 能做什么?
实现方式
启动 JVM 时加载 Agent(premain)
定义 Agent
1 2 3 4 5 6 7 8 9 10 11
| public class MyAgent {
public static void premain(String[] args, Instrumentation instrumentation) {
System.out.println("JVM starting, load agent");
}
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| Manifest-Version: 1.0
Premain-Class: org.example.agent.MyAgent
Agent-Class: org.example.agent.MyAgent
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Can-Set-Native-Method-Prefix: true
|
修改 POM 文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
</plugins>
</build>
|
打包 mvn assembly:assembly 进行打包,会生成2个jar包,my-agent-1.0-SNAPSHOT.jar中不带这个项目所依赖的jar包,my-agent-1.0-SNAPSHOT-jar-with-dependencies.jar中包含这个项目所依赖的jar包,后面需要使用my-agent-1.0-SNAPSHOT-jar-with-dependencies.jar这个jar
项目工程引入自定义 agent ,在项目启动时 添加 vm 参数,-javaagent={agentpath}/myagent.jar
JVM 运行时加载 agent(attachemain)
- 该方法就不是使用 -javaagent 参数引入,需要使用 virtualMachine 下的 attche 方法引入,该类不是 jdk 官方提供,又sun公司提供,需要引入依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class Attacher {
public static void main(String[] args)
throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException {
VirtualMachine vm = VirtualMachine.attach(args[0]);
vm.loadAgent(
"/Users/fisher/Documents/code/gitee/myAgent/target/my-agent-1.0-SNAPSHOT-jar-with-dependencies.jar",
"Hello JVM Attach");
vm.detach();
}
}
|
打包 POM
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| <build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.5</version>
<configuration>
<archive>
<manifest>
<mainClass>org.example.attach.Attacher</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
|
利用 jps 查看进程号,选择要加载agent的进程号,启动 agent 传入 进程号,完成 agent 的载入