Instrumentation 是什么?¶
结论¶
java.lang.instrument 是 JDK 提供的 Java Agent API,允许在不修改源码的前提下,在 JVM 启动时或运行期对类的字节码进行增强(修改、替换、监控)。
典型应用:Arthas、SkyWalking、Pinpoint、Jacoco、热部署(JRebel)。
两种使用方式¶
1. 启动时加载(Premain)¶
JVM 启动参数加:
Agent jar 的 MANIFEST.MF 必须声明:
Agent 类实现:
public class MyAgent {
public static void premain(String agentArgs, Instrumentation inst) {
inst.addTransformer(new MyTransformer());
}
}
MyTransformer 实现 ClassFileTransformer,在类加载时拦截字节码:
public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer) {
if (className.equals("com/example/Service")) {
// 用 ASM / Javassist / ByteBuddy 修改字节码
return enhance(classfileBuffer);
}
return classfileBuffer;
}
2. 运行期加载(Agentmain)¶
JVM 启动后用 VirtualMachine.attach(pid) 动态挂载:
VirtualMachine vm = VirtualMachine.attach("12345");
vm.loadAgent("/path/to/agent.jar");
vm.detach();
Agent 类实现 agentmain,用于 Arthas 这种"连上即可用"的工具。
核心 API¶
| 方法 | 作用 |
|---|---|
addTransformer(ClassFileTransformer) |
注册转换器 |
retransformClasses(Class...) |
重新触发 transform |
redefineClasses(ClassDefinition...) |
直接替换类定义 |
getAllLoadedClasses() |
获取所有已加载类 |
appendToBootstrapClassLoaderSearch |
向 Boot ClassPath 追加 jar |
字节码增强工具¶
- ASM:底层、高性能、学习陡。
- Javassist:API 友好,性能略低。
- ByteBuddy:现代推荐,封装 ASM,SkyWalking 用它。
典型应用¶
- APM 监控:SkyWalking、Pinpoint 埋点方法耗时。
- 线上诊断:Arthas watch/trace。
- 覆盖率:JaCoCo 插桩。
- 热部署:JRebel。
- 日志增强:自动打印方法入参出参。
限制
redefineClasses不能加方法、加字段、改继承关系,只能改方法体。- 频繁 retransform 会引起 Metaspace 膨胀。
- 生产环境谨慎使用,字节码写错可能导致 JVM crash。