如何用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
相关产品推荐
相关产品推荐

