You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Byte Buddy/ASM插装JDK8代码采集变量分配及方法参数数据

选择Byte Buddy实现JDK8下的Java代码插装需求

优先选Byte Buddy来实现你的需求,ASM虽然是字节码操作的基础库,但需要手动处理大量底层字节码指令,开发成本高且容易出错;Byte Buddy提供了高阶封装的API,能快速实现方法参数采集和对象分配追踪,同时完美适配JDK8的参数名获取逻辑。

Byte Buddy的核心优势

  • 简化字节码操作:无需手动编写字节码指令,通过注解式的Advice就能定义插装逻辑,大幅降低开发复杂度。
  • 原生支持参数名获取:JDK8编译时添加-parameters参数后,Byte Buddy可以直接通过MethodDescription获取方法的原始参数名,无需额外解析字节码元数据。
  • 集成对象分配追踪:结合AgentBuilder和构造方法插装,能轻松采集对象分配的类型和实例信息。

示例实现代码

1. 插装代理(Agent)代码

import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatchers;

import java.lang.instrument.Instrumentation;
import java.util.stream.Collectors;

public class AllocationAndParameterAgent {
    public static void premain(String args, Instrumentation inst) {
        new AgentBuilder.Default()
                // 匹配需要插装的目标类(可根据业务调整范围)
                .type(ElementMatchers.nameStartsWith("com.yourpackage"))
                // 插装所有非构造方法,采集参数信息
                .transform((builder, typeDesc, classLoader, module) -> builder
                        .visit(Advice.to(MethodParameterAdvice.class)
                                .on(ElementMatchers.not(ElementMatchers.isConstructor()))))
                // 插装构造方法,追踪对象分配
                .transform((builder, typeDesc, classLoader, module) -> builder
                        .visit(Advice.to(AllocationAdvice.class)
                                .on(ElementMatchers.isConstructor())))
                .installOn(inst);
    }

    // 方法参数采集逻辑
    public static class MethodParameterAdvice {
        @Advice.OnMethodEnter
        public static void captureParams(
                @Advice.Origin MethodDescription method,
                @Advice.AllArguments Object[] args) {
            // 获取参数名列表
            String paramNames = method.getParameters()
                    .stream()
                    .map(param -> param.getInternalName())
                    .collect(Collectors.joining(", "));
            // 获取参数值列表
            String paramValues = args == null ? "无参数" :
                    java.util.Arrays.stream(args)
                            .map(obj -> obj == null ? "null" : obj.toString())
                            .collect(Collectors.joining(", "));

            // 输出格式化日志
            System.out.printf("[方法调用] %s.%s | 参数名: [%s] | 参数值: [%s]%n",
                    method.getDeclaringType().getSimpleName(),
                    method.getName(),
                    paramNames,
                    paramValues);
        }
    }

    // 对象分配采集逻辑
    public static class AllocationAdvice {
        @Advice.OnMethodExit
        public static void captureAllocation(@Advice.This Object instance) {
            System.out.printf("[对象分配] 类型: %s | 实例哈希: %d%n",
                    instance.getClass().getSimpleName(),
                    instance.hashCode());
        }
    }
}

2. 测试代码

public class TestApp {
    public static void main(String[] args) {
        User user = createUser("Alice", 25);
        printUserInfo(user);
    }

    public static User createUser(String name, int age) {
        return new User(name, age);
    }

    public static void printUserInfo(User user) {
        System.out.println("User Info: " + user.getName() + ", " + user.getAge());
    }
}

class User {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

期望输出格式

[方法调用] TestApp.main | 参数名: [args] | 参数值: [[Ljava.lang.String;@xxxxxx]
[方法调用] TestApp.createUser | 参数名: [name, age] | 参数值: [Alice, 25]
[对象分配] 类型: User | 实例哈希: xxxxx
[方法调用] TestApp.printUserInfo | 参数名: [user] | 参数值: [User@xxxxxx]
User Info: Alice, 25

关键注意事项

  • 编译Java代码时必须添加-parameters参数,确保参数名被保留到class文件中,否则Byte Buddy无法获取原始参数名。
  • 引入Byte Buddy依赖(Maven示例):
<dependency>
    <groupId>net.bytebuddy</groupId>
    <artifactId>byte-buddy</artifactId>
    <version>1.14.11</version>
</dependency>
<dependency>
    <groupId>net.bytebuddy</groupId>
    <artifactId>byte-buddy-agent</artifactId>
    <version>1.14.11</version>
</dependency>
  • 运行测试程序时,通过-javaagent指定代理Jar:
java -javaagent:allocation-agent.jar TestApp

内容的提问来源于stack exchange,提问作者farzad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 04:20:16