JavaAgent插桩技术介绍
Java 代理(agent)是一种拦截处理技术,它会在你的 Java 代码执行前进行拦截并按照你的要求进行字节码调整。
我们开发中使用的很多工具都是基于 Java 代理来实现的,比如 JRebel、以及诊断工具等。
Java Agent规范
因为其特殊性,Java Agent 规定,需要在 META-INF
目录下创建 MANIFEST.MF
文件,并在其内部指定 Agent 的启动类:
Manifest-Version: 1.0
Premain-Class: org.example.App
Archiver-Version: Plexus Archiver
Built-By: jack
Agent-Class: org.example.App
Created-By: Apache Maven 3.2.5
Build-Jdk: 1.8.0_40
上述仅为示例文件,具体配置请根据实际情况处理
Java Agent 入口类
上述配置中设置了Premain-Class
和Agent-Class
的类路径,这代表着我们的 Agent 在不同的运行方式下会找不同的入口类。
Premain-Class
代表的是以-javaagent:*
的方式载入时,Agent 程序的入口类路径。
-javaagent:/jetbrains-all/current/ja-netfilter.jar=jetbrains
Agent-Class
则代表的是以 Attach API 的方式载入时,Agent 程序的入口类路径。
public class Attacher {
public static void main(String[] args) throws AttachNotSupportedException, IOException, AgentLoadException, AgentInitializationException {
// 传入目标 JVM pid
VirtualMachine vm = VirtualMachine.attach("39333");
vm.loadAgent("/jetbrains-all/current/ja-netfilter.jar");
}
}
入口类的定义如下:
public class App {
/**
* 以vm参数的方式载入,在Java程序的main方法执行之前执行
*/
public static void premain(String agentArgs, Instrumentation inst) {}
/**
* 以Attach的方式载入,在Java程序启动后执行
*/
public static void agentmain(String agentArgs, Instrumentation inst) {}
}
Maven Build
为了便于打包,一般我们会使用 Maven 的 Plugin 进行自动配置:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<!--自动添加META-INF/MANIFEST.MF -->
<manifest>
<addClasspath>true</addClasspath>
</manifest>
<manifestEntries>
<Premain-Class>com.rickiyang.learn.PreMainTraceAgent</Premain-Class>
<Agent-Class>com.rickiyang.learn.PreMainTraceAgent</Agent-Class>
<Can-Redefine-Classes>true</Can-Redefine-Classes>
<Can-Retransform-Classes>true</Can-Retransform-Classes>
</manifestEntries>
</archive>
</configuration>
</plugin>
使用场景
Java Agent 结合 ASM 技术可以做到很多事情,主要包含以下几种场景:
- 日志记录
- 性能分析
- 热部署
- Mock服务
- 动态数据映射
- ……
JavaAgent插桩技术介绍
https://blog.cikaros.top/doc/492edb0a.html