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

如何使用Byte-Buddy自定义Implementation重定义第三方类方法?

Byte-Buddy自定义Implementation实现方法参数修改

需求场景

现有第三方Demo类:

class Demo{
    public void handle(String value) {
        // 原有业务逻辑
    }
}

需要在handle方法执行时,自动将输入参数value转换为小写,最终实现逻辑等价于:

class Demo{
    public void handle(String value) {
        value = value.toLowerCase();
        // 原有业务逻辑
    }
}

由于需要重定义类,无法使用Byte-Buddy的MethodDelegation,需通过自定义Implementation直接编写字节码实现。

已有代码框架

DynamicType.Loaded<SumExample> loaded = new ByteBuddy()
    .subclass(Demo.class)
    .method(named("handle"))
    .intercept(MyImplementation.INSTANCE)
    .make()
    .load(Thread.currentThread().getContextClassLoader(), ClassLoadingStrategy.Default.WRAPPER);

// 自定义Implementation实现类
enum MyImplementation implements Implementation {

    INSTANCE; // 单例实例

    @Override
    public InstrumentedType prepare(InstrumentedType instrumentedType) {
        return instrumentedType;
    }

    @Override
    public ByteCodeAppender appender(Target implementationTarget) {
        return MyAppender.INSTANCE;
    }

}
 
// 需要完善的ByteCodeAppender实现
enum MyAppender implements ByteCodeAppender {

    INSTANCE; // 单例实例

    @Override
    public Size apply(MethodVisitor methodVisitor,
                      Implementation.Context implementationContext,
                      MethodDescription instrumentedMethod) {
        methodVisitor.visitCode();
        // 待填充字节码逻辑
        methodVisitor.visitEnd();
        return new Size(0, instrumentedMethod.getStackSize());
    }
}

完善后的MyAppender实现

下面是填充后的字节码编写逻辑,包含参数小写转换、父类方法调用,还可按需添加非空检查:

import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Label;

// ...

@Override
public Size apply(MethodVisitor methodVisitor,
                  Implementation.Context implementationContext,
                  MethodDescription instrumentedMethod) {
    methodVisitor.visitCode();

    // 可选:添加参数非空检查
    Label notNullLabel = new Label();
    methodVisitor.visitVarInsn(Opcodes.ALOAD, 1); // 加载参数value到栈顶
    methodVisitor.visitJumpInsn(Opcodes.IFNONNULL, notNullLabel);
    // 若value为null,抛出NullPointerException
    methodVisitor.visitTypeInsn(Opcodes.NEW, "java/lang/NullPointerException");
    methodVisitor.visitInsn(Opcodes.DUP);
    methodVisitor.visitLdcInsn("Parameter 'value' cannot be null");
    methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/NullPointerException", "<init>", "(Ljava/lang/String;)V", false);
    methodVisitor.visitInsn(Opcodes.ATHROW);
    methodVisitor.visitLabel(notNullLabel);

    // 核心逻辑:将value转换为小写并更新参数
    methodVisitor.visitVarInsn(Opcodes.ALOAD, 1); // 加载原value参数
    // 调用String.toLowerCase()方法
    methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
                                  "java/lang/String",
                                  "toLowerCase",
                                  "()Ljava/lang/String;",
                                  false);
    methodVisitor.visitVarInsn(Opcodes.ASTORE, 1); // 将小写结果存回value参数

    // 调用父类Demo的handle方法,执行原有业务逻辑
    methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); // 加载当前实例this
    methodVisitor.visitVarInsn(Opcodes.ALOAD, 1); // 加载更新后的value参数
    // 注意:替换"com/example/Demo"为Demo类的实际全限定类名(用/分隔包路径)
    methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL,
                                  "com/example/Demo",
                                  "handle",
                                  "(Ljava/lang/String;)V",
                                  false);

    // 方法返回
    methodVisitor.visitInsn(Opcodes.RETURN);

    methodVisitor.visitEnd();
    // 栈最大深度为2(调用父类方法时需同时容纳this和value两个引用),局部变量数沿用原方法配置
    return new Size(2, instrumentedMethod.getStackSize());
}

代码说明

  1. 非空检查(可选):通过字节码判断value是否为null,若为null则抛出异常,避免后续调用toLowerCase()时出现空指针。
  2. 参数小写转换:
    • ALOAD 1:将局部变量表中索引1的value参数加载到操作数栈顶(实例方法中,索引0为this,第一个参数从索引1开始)。
    • INVOKEVIRTUAL:调用String.toLowerCase()方法,栈顶变为转换后的小写字符串。
    • ASTORE 1:将小写结果存回局部变量表的索引1位置,完成value = value.toLowerCase()的赋值操作。
  3. 调用父类方法:通过INVOKESPECIAL调用父类Demo的handle方法,确保原有业务逻辑被执行。
  4. 栈大小配置:设置栈最大深度为2,因为调用父类方法时,操作数栈需要同时容纳this和value两个对象引用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 06:25:01