跳转至

Instrumentation 是什么?

结论

java.lang.instrument 是 JDK 提供的 Java Agent API,允许在不修改源码的前提下,在 JVM 启动时或运行期对类的字节码进行增强(修改、替换、监控)。

典型应用:Arthas、SkyWalking、Pinpoint、Jacoco、热部署(JRebel)。

两种使用方式

1. 启动时加载(Premain)

JVM 启动参数加:

-javaagent:/path/to/agent.jar=arg1

Agent jar 的 MANIFEST.MF 必须声明:

Premain-Class: com.example.MyAgent
Can-Redefine-Classes: true
Can-Retransform-Classes: true

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。