bigywater.tech
Java · 201

Java Instrumentation:在类加载时插入观测逻辑

在类加载时插入观测逻辑,是 APM 与各种监控 agent 的基本做法。这篇自己写一个 Java agent(premain + ClassFileTransformer + ASM),验证它能看到哪些类、怎么插桩、失败时是什么样(Attach 与运行中修改在后面的篇目)。

809 个
premain 开始时已加载、transformer 看不到的类数
6 次
transformer 之后被调用的次数(新加载的类)
静默
transformer 抛异常时没有任何输出

没有 agent

实测 · 本机执行输出
  [app] work(1000000) = 2999997,hello = hello agent
  [app] Other.go() 运行
  [agent] transformer 一共被调用 0 次;其中 demo 包的类:[]

premain 与 transformer

实测 · 本机执行输出
  [agent] premain 开始,此时已经加载的类数 = 809,支持 retransform = true,参数 = log
  [app] work(1000000) = 2999997,hello = hello agent
  [app] Other.go() 运行
  [agent] transformer 一共被调用 6 次;其中 demo 包的类:[demo/Target, demo/Other]

插入计时

实测 · 本机执行输出
  [agent] premain 开始,此时已经加载的类数 = 809,支持 retransform = true,参数 = time
  [agent] 方法 work 耗时 1795 µs(由 agent 在字节码里插入的计时)
  [agent] 方法 hello 耗时 86 µs(由 agent 在字节码里插入的计时)
  [app] work(1000000) = 2999997,hello = hello agent
  [app] Other.go() 运行
  [agent] transformer 一共被调用 6 次;其中 demo 包的类:[demo/Target, demo/Other]

transformer 异常

实测 · 本机执行输出
  [agent] premain 开始,此时已经加载的类数 = 809,支持 retransform = true,参数 = boom
  [app] work(1000000) = 2999997,hello = hello agent
  [app] Other.go() 运行
  [agent] transformer 一共被调用 6 次;其中 demo 包的类:[demo/Target, demo/Other]

分步演示

Java Instrumentation
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12,ASM 9.7(asm、asm-commons,Maven 解析)
    • 没有验证:retransform 与 redefine、agentmain 与 attach(后面的篇目)、多个 agent 的 transformer 顺序、对 JDK 核心类的插桩、插桩对性能的影响(只打印了插入的计时本身)、-Xshare 的 CDS 归档对 transformer 的影响;premain 前的类数随 JDK 与参数变化
    京ICP备2026067502号-1京公网安备11010502063487号