Java Agent premain与agentmain详解及Arthas原理
深入分析Java Agent的premain(启动时加载)和agentmain(运行时Attach)两种模式,以及诊断工具Arthas利用Agent实现热替换、方法追踪的核心原理。
回答
小字辈
1. premain模式
// 启动时执行,在main方法之前
public static void premain(String agentArgs, Instrumentation inst) {
// 添加ClassFileTransformer,在类加载时修改字节码
inst.addTransformer(new MyTransformer());
}
- 打包要求:MANIFEST.MF必须包含
Premain-Class - 启动命令:
java -javaagent:agent.jar -jar app.jar - 限制:只能拦截加载前的类,已加载的类无法修改
2. agentmain模式
// 运行时动态附加到JVM
public static void agentmain(String agentArgs, Instrumentation inst) {
inst.addTransformer(new MyTransformer(), true);
// 对已加载的类重新转换
inst.retransformClasses(TargetClass.class);
}
- 打包要求:MANIFEST.MF必须包含
Agent-Class和Can-Retransform-Classes: true - Attach API(
com.sun.tools.attach.VirtualMachine):VirtualMachine vm = VirtualMachine.attach(pid); // 附加到目标进程 vm.loadAgent(agentJarPath, args); // 加载Agent vm.detach(); // 分离
3. Arthas原理深度解析
- Attach到目标JVM:使用VirtualMachine.attach(pid)
- 核心组件:
- Instrumentation:retransformClasses动态替换字节码
- ASM/Byte Buddy:修改字节码插入监控逻辑
- SPI加载:自定义ClassLoader加载Arthas的Class
- watch/trace命令:通过Instrumentation + ASM在方法前后插入切面
- ognl表达式:利用ognl提取上下文变量
- 热替换(redefine):
retransformClasses实现方法替换
4. 注意事项
- MANIFEST.MF需设置
Can-Retransform-Classes: true - agentmain需要tools.jar(JDK 8)或jdk.attach模块(JDK 9+)