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

如何用Byte Buddy实现Cache子类的load/dump字段映射逻辑?

问题描述

我有一个抽象类Cache:

public abstract class Cache {
    public abstract void load(Object input);
    public abstract void dump(Object output);
}

想通过Byte Buddy创建它的子类,需求如下:

  • 定义若干字段(这部分已经实现)
  • 实现两个抽象方法:
    • load:把Input对象的同名字段值赋值给Cache子类的对应字段
    • dump:把Cache子类的字段值赋值给Output对象的对应字段

试过FieldAccessor API,但不太适配这个场景,只找到一个早期相关讨论但没可用代码。

示例场景

给定Input和Output类:

public class Input {
   double foo;
   String bar;
}
public class Output {
   boolean z;
}

需要生成这样的Cache子类:

public class ByteBuddyCache extends Cache {

    double foo;
    String bar;
    boolean z;

    public void load(Object input) {
        Input i = (Input) input;
        this.foo = i.foo;
        this.bar = i.bar;
    }
    public void dump(Object output) {
        Output o = (Output) output;
        o.z = this.z;
    }
}

解决方案

有两种实现方式,一种是用MethodDelegation结合反射(简单易读),另一种是直接生成字节码(性能更高),按需选择:

方式一:MethodDelegation + 反射实现(快速开发)

这种方式通过委托拦截器处理字段赋值逻辑,代码简洁易懂:

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.field.FieldDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class CacheGenerator {

    public static Cache generate(Class<?> inputClass, Class<?> outputClass) throws Exception {
        List<Field> inputFields = getAllFields(inputClass);
        List<Field> outputFields = getAllFields(outputClass);

        // 构建动态子类
        DynamicType.Builder<Cache> builder = new ByteBuddy()
                .subclass(Cache.class)
                .name("ByteBuddyCache");

        // 添加对应字段
        for (Field f : inputFields) {
            builder = builder.defineField(f.getName(), f.getType(), FieldDescription.Token.Visibility.PUBLIC);
        }
        for (Field f : outputFields) {
            builder = builder.defineField(f.getName(), f.getType(), FieldDescription.Token.Visibility.PUBLIC);
        }

        // 实现load方法
        builder = builder.method(ElementMatchers.named("load"))
                .intercept(MethodDelegation.to(new LoadHandler(inputClass, inputFields)));

        // 实现dump方法
        builder = builder.method(ElementMatchers.named("dump"))
                .intercept(MethodDelegation.to(new DumpHandler(outputClass, outputFields)));

        // 生成并实例化
        return builder.make().load(CacheGenerator.class.getClassLoader()).getLoaded().newInstance();
    }

    // 递归获取类及父类的所有字段
    private static List<Field> getAllFields(Class<?> clazz) {
        List<Field> fields = new ArrayList<>();
        Class<?> current = clazz;
        while (current != Object.class) {
            fields.addAll(List.of(current.getDeclaredFields()));
            current = current.getSuperclass();
        }
        return fields;
    }

    // Load方法处理器
    public static class LoadHandler {
        private final Class<?> inputType;
        private final List<Field> inputFields;

        public LoadHandler(Class<?> inputType, List<Field> inputFields) {
            this.inputType = inputType;
            this.inputFields = inputFields;
        }

        public void handle(Object cache, Object input) throws Exception {
            Object castInput = inputType.cast(input);
            for (Field f : inputFields) {
                Field cacheField = cache.getClass().getDeclaredField(f.getName());
                cacheField.setAccessible(true);
                cacheField.set(cache, f.get(castInput));
            }
        }
    }

    // Dump方法处理器
    public static class DumpHandler {
        private final Class<?> outputType;
        private final List<Field> outputFields;

        public DumpHandler(Class<?> outputType, List<Field> outputFields) {
            this.outputType = outputType;
            this.outputFields = outputFields;
        }

        public void handle(Object cache, Object output) throws Exception {
            Object castOutput = outputType.cast(output);
            for (Field f : outputFields) {
                Field cacheField = cache.getClass().getDeclaredField(f.getName());
                cacheField.setAccessible(true);
                f.setAccessible(true);
                f.set(castOutput, cacheField.get(cache));
            }
        }
    }
}

方式二:直接生成字节码(高性能)

如果追求极致性能,直接用ByteCodeAppender生成ASM指令,完全模拟手写Java代码的字节码逻辑:

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.field.FieldDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.ByteCodeAppender;
import net.bytebuddy.matcher.ElementMatchers;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class HighPerfCacheGenerator {

    public static Cache generate(Class<?> inputClass, Class<?> outputClass) throws Exception {
        List<Field> inputFields = getAllFields(inputClass);
        List<Field> outputFields = getAllFields(outputClass);

        DynamicType.Builder<Cache> builder = new ByteBuddy()
                .subclass(Cache.class)
                .name("ByteBuddyCache");

        // 添加字段
        for (Field f : inputFields) {
            builder = builder.defineField(f.getName(), f.getType(), FieldDescription.Token.Visibility.PUBLIC);
        }
        for (Field f : outputFields) {
            builder = builder.defineField(f.getName(), f.getType(), FieldDescription.Token.Visibility.PUBLIC);
        }

        // 实现load方法
        builder = builder.method(ElementMatchers.named("load"))
                .intercept(new ByteCodeAppender() {
                    @Override
                    public Size apply(MethodVisitor mv, Context ctx, MethodDescription md) {
                        // 类型转换:Object -> Input
                        mv.visitVarInsn(Opcodes.ALOAD, 1);
                        mv.visitTypeInsn(Opcodes.CHECKCAST, inputClass.getName().replace('.', '/'));
                        mv.visitVarInsn(Opcodes.ASTORE, 2);

                        // 逐个字段赋值
                        for (Field f : inputFields) {
                            String inputInternalName = inputClass.getName().replace('.', '/');
                            String cacheInternalName = ctx.getTypeDescription().getInternalName();
                            String fieldDesc = TypeDescription.ForLoadedType.of(f.getType()).getDescriptor();

                            // this.foo = i.foo
                            mv.visitVarInsn(Opcodes.ALOAD, 0);
                            mv.visitVarInsn(Opcodes.ALOAD, 2);
                            mv.visitFieldInsn(Opcodes.GETFIELD, inputInternalName, f.getName(), fieldDesc);
                            mv.visitFieldInsn(Opcodes.PUTFIELD, cacheInternalName, f.getName(), fieldDesc);
                        }

                        mv.visitInsn(Opcodes.RETURN);
                        return new Size(3, 3);
                    }
                });

        // 实现dump方法
        builder = builder.method(ElementMatchers.named("dump"))
                .intercept(new ByteCodeAppender() {
                    @Override
                    public Size apply(MethodVisitor mv, Context ctx, MethodDescription md) {
                        // 类型转换:Object -> Output
                        mv.visitVarInsn(Opcodes.ALOAD, 1);
                        mv.visitTypeInsn(Opcodes.CHECKCAST, outputClass.getName().replace('.', '/'));
                        mv.visitVarInsn(Opcodes.ASTORE, 2);

                        // 逐个字段赋值
                        for (Field f : outputFields) {
                            String outputInternalName = outputClass.getName().replace('.', '/');
                            String cacheInternalName = ctx.getTypeDescription().getInternalName();
                            String fieldDesc = TypeDescription.ForLoadedType.of(f.getType()).getDescriptor();

                            // o.z = this.z
                            mv.visitVarInsn(Opcodes.ALOAD, 2);
                            mv.visitVarInsn(Opcodes.ALOAD, 0);
                            mv.visitFieldInsn(Opcodes.GETFIELD, cacheInternalName, f.getName(), fieldDesc);
                            mv.visitFieldInsn(Opcodes.PUTFIELD, outputInternalName, f.getName(), fieldDesc);
                        }

                        mv.visitInsn(Opcodes.RETURN);
                        return new Size(3, 3);
                    }
                });

        return builder.make().load(HighPerfCacheGenerator.class.getClassLoader()).getLoaded().newInstance();
    }

    private static List<Field> getAllFields(Class<?> clazz) {
        List<Field> fields = new ArrayList<>();
        Class<?> current = clazz;
        while (current != Object.class) {
            fields.addAll(List.of(current.getDeclaredFields()));
            current = current.getSuperclass();
        }
        return fields;
    }
}

使用示例

public class Main {
    public static void main(String[] args) throws Exception {
        Cache cache = CacheGenerator.generate(Input.class, Output.class);

        // 测试load
        Input input = new Input();
        input.foo = 1.23;
        input.bar = "test";
        cache.load(input);

        // 测试dump
        Output output = new Output();
        cache.dump(output);
        System.out.println(output.z); // 输出初始值false
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 03:18:11