自动注入代码技术之java agent
笔者这段时间调研和推动了“流量回归测试产品”,大体玩法是通过录制线上的真实流量,包括http,redis, mysql, Apollo等,在测试环境进行流量回放,通过代码覆盖率来对质量测试做提效。
而这里采用的关键技术就是Java agent, 就我们目前使用的情况来看,这类字节码增强非常强大,不过线上使用的稳定性方面要额外关注,特别是attach时候,对cpu和mem的影响。
本文只是想对Java agent做一个简单的介绍,想讲清楚它是什么,能做什么,谁在用这些内容。
1. 什么是 Java Agent
Java Agent 是 Java 平台提供的一种工具包,允许开发者在 Java 虚拟机(JVM)启动后或运行时,修改已有程序的字节码,从而实现方法级别的增强或监控。简单来说,它让你能够在不修改源代码的情况下,动态地改变程序的行为。
从 JDK 5 开始引入,Java Agent 一直是 JVM 层级的观测、调试和增强基础设施的重要部分。
2. 技术原理
2.1 核心机制:字节码插桩
Java Agent 的底层机制是字节码插桩。当 JVM 加载类时,Agent 可以通过 java.lang.instrument 包提供的 API,拦截类加载过程,修改其字节码后再交给 JVM 执行。这种修改可以发生在:
· 类加载时:在类被定义到 JVM 之前进行转换。
· 类加载后:对已经加载的类进行重新转换(retransform)。

2.2 核心组件
Agent 的实现依赖两个核心组件:
· Instrumentation 接口:这是 Agent 与 JVM 交互的核心。通过它,Agent 可以注册类转换器、获取已加载的类、重定义类等。
· Agent 类:包含 premain 或 agentmain 方法的普通 Java 类,作为 Agent 的入口。

2.3 启动模式与生命周期
Java Agent 支持两种启动模式,对应不同的入口方法:

启动模式 入口方法 触发时机 典型应用场景
静态启动 premain JVM 启动时,main 方法执行前 应用启动即需要监控(如 APM 探针)
动态启动 agentmain JVM 运行中(通过 Attach 机制) 线上故障排查、热更新

工作流程:
1. JVM 启动或接收到 Attach 请求。
2. 加载 Agent JAR 文件,读取 MANIFEST.MF 中的入口类配置(如 Premain-Class)。
3. JVM 调用 Agent 类的 premain 或 agentmain 方法,并传入 Instrumentation 实例。
4. Agent 通过 Instrumentation 注册 ClassFileTransformer,实现字节码修改逻辑。
2.4 MANIFEST.MF 关键属性
Agent JAR 包的清单文件(MANIFEST.MF)必须包含特定属性来告诉 JVM 如何启动 Agent:
属性介绍:
Premain-Class
静态启动时,指定包含 premain 方法的类(必需)。
Agent-Class
动态启动时,指定包含 agentmain 方法的类(必需)。
Launcher-Agent-Class
可执行 JAR 中,指定在 main 前启动的 Agent 类。
Boot-Class-Path
指定需要由引导类加载器加载的路径,用于增强 JDK 核心类。
Can-Redefine-Classes
声明 Agent 是否可以重定义类(默认为 false)。
Can-Retransform-Classes
声明 Agent 是否可以重新转换类(默认为 false)。
3. 使用方式
3.1 静态启动(premain)
这是最常见的启动方式,通过在 JVM 启动参数中添加 -javaagent 来实现。
步骤 1:编写 Agent 类
```java
import java.lang.instrument.Instrumentation;
public class MyAgent {
// 方法签名一(优先被调用)
public static void premain(String agentArgs, Instrumentation inst) {
System.out.println("MyAgent 已启动,参数:" + agentArgs);
// 在这里添加 ClassFileTransformer 进行字节码修改
}
// 方法签名二(备用)
public static void premain(String agentArgs) {
System.out.println("MyAgent 已启动(简单模式),参数:" + agentArgs);
}
}
```
步骤 2:打包并配置 MANIFEST.MF
使用 Maven 的 maven-assembly-plugin 或手动创建,确保 MANIFEST.MF 包含:
```
Premain-Class: com.example.MyAgent
Can-Retransform-Classes: true
```
步骤 3:启动应用程序
```bash
java -javaagent:/path/to/my-agent.jar=optionalArgs -jar my-application.jar
```
3.2 动态启动(agentmain)
动态启动允许在 JVM 运行后附加 Agent,常用于诊断工具。这通常需要借助 com.sun.tools.attach API 或 jattach 等工具。
步骤 1:编写 Agent 类
```java
import java.lang.instrument.Instrumentation;
public class MyDynamicAgent {
public static void agentmain(String agentArgs, Instrumentation inst) {
System.out.println("动态 Agent 已附加,参数:" + agentArgs);
// 在这里执行运行时诊断或增强
}
}
```
MANIFEST.MF 需要指定 Agent-Class。
步骤 2:编写 Attach 程序
```java
import com.sun.tools.attach.VirtualMachine;
public class Attacher {
public static void main(String[] args) throws Exception {
VirtualMachine vm = VirtualMachine.attach("进程ID"); // 目标 JVM 的 PID
vm.loadAgent("/path/to/my-dynamic-agent.jar", "args");
vm.detach();
}
}
```
注意:
从 JDK 9 开始,动态加载 Agent 需要目标 JVM 启用
-XX:+EnableDynamicAgentLoading
参数。
4. 框架与生态支持
Java Agent 技术已被广泛集成到各类工具和框架中,尤其是可观测性领域。以下列举了主流生态的支持情况。
4.1 可观测性(APM / 监控)
这是 Java Agent 应用最广泛的领域。许多 APM(应用性能监控)工具通过 Agent 实现零代码侵入的埋点。
OpenTelemetry Java Agent
OpenTelemetry 提供了一个功能强大的 Java Agent,能够自动为数百个常用库和框架生成追踪、度量和日志数据,而无需修改代码。其支持的部分框架包括:
Web 框架
Spring Boot 2.x/3.x, Spring WebFlux, JAX-RS, Jersey, Tomcat, Jetty, Undertow
数据访问 JDBC, Cassandra Driver, Elasticsearch Client, MongoDB Driver, Redis (Jedis/Lettuce)
消息中间件
Kafka, JMS, ActiveMQ, RabbitMQ, RocketMQ
RPC 客户端
gRPC, Apache HttpClient, OkHttp, AWS SDK
异步框架
Executors, Kotlin Coroutines, Akka Actors, RxJava
其他类似工具如 AppDynamics、Splunk 等同样提供了基于 Agent 的自动 instrumentation 能力,支持 Spring Boot、Struts、WebLogic 等企业级框架。
4.2 性能剖析与诊断
· JProfiler / YourKit:
商业性能分析工具,通过 Agent 收集 CPU、内存等运行时数据。
· Alibaba Arthas:
开源的 Java 诊断工具,利用 Agent 实现在线排查问题,如方法调用追踪、参数实时监控等。
4.3 新一代 AI Agent 框架
需要特别注意术语的区别:传统的 Java Agent(java.lang.instrument)是 JVM 层面的技术;而近期出现的“AI Agent”框架(如 Spring AI Agents、Google ADK)指的是应用层的人工智能代理。两者是不同的概念。
然而,AI 领域的互操作性协议 Agent2Agent (A2A) 已经开始拥抱 Java 生态。由 Quarkus 和 WildFly 团队主导开发的 A2A Java SDK,允许 Java 开发者构建能够与 Python、JavaScript 等其他语言 Agent 通信的 AI Agent。这标志着 Java 在 AI 时代依然扮演着重要的基础设施角色。
5. 流行项目应用案例
Java Agent 技术已经在业界头部项目中得到广泛应用:
OpenTelemetry
提供官方的 Java Agent,作为可观测性数据的标准采集器,被大量企业用于统一监控体系。
New Relic / Dynatrace
商业 APM 产品的核心探针均基于 Java Agent 技术实现。
IntelliJ IDEA
其调试器在 HotSwap 等特性中利用 Agent 能力实现部分代码的热替换。
SkyWalking
国产开源 APM 系统,其 Java Agent 是其主要的数据收集方式。
Spring AI Agents
虽然属于应用层 AI 框架,但其底层工具链(如基准测试套件)可能会涉及 JVM 层面的观测技术。
6. 总结与最佳实践
6.1 能干什么?
· 观测:自动埋点,实现分布式追踪、性能监控。
· 诊断:在线查看方法参数、返回值、异常,无需重启应用。
· 增强:为遗留系统添加统一的功能,如日志 MDC、鉴权等。
· 热更新:在不重启的情况下修改部分类逻辑。
6.2 注意事项
· 性能开销:字节码转换和增强逻辑会带来额外的 CPU 和内存开销,需在生产环境充分测试。
· 兼容性:Agent 可能与应用本身或其它 Agent 发生冲突(如字节码顺序问题)。
· 安全性:Agent 拥有修改任何类的能力,部署来源不明的 Agent 存在巨大安全风险,必须验证其可信度。
· 权限:动态加载 Agent 在 JDK 9+ 需要显式启用。
6.3 选择建议
· 若需要开箱即用的可观测性,优先考虑 OpenTelemetry Java Agent。
· 若需定制化字节码增强,可基于 java.lang.instrument 开发轻量级 Agent。
· 若目标是 AI 应用互操作,可关注 A2A Java SDK 的发展。
7. 参考资料
https://docs.oracle.com/en/java/javase/24/docs/api/java.instrument/java/lang/instrument/package-summary.html
https://glaforge.dev/posts/2025/05/20/writing-java-ai-agents-with-adk-for-java-getting-started/#_
https://help.splunk.com/en/appdynamics-on-premises/virtual-appliance-self-hosted/25.7.0/splunk-appdynamics-for-opentelemetry/support-for-appdynamics-for-opentelemetry/java-agent-frameworks-for-opentelemetry
https://springframework.org.cn/blog/2025/10/28/agents-and-benchmarks/
https://opentelemetry.bayern/docs/zero-code/java/agent/supported-libraries/
https://docs.oracle.com/en/java/javase/11/docs/api/java.instrument/java/lang/instrument/package-summary.html?is-external=true
https://spring.io/blog/2025/10/28/agents-and-benchmarks
更多推荐



所有评论(0)