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

如何用ByteBuddy创建运行时方法代理?重定义后无法调用原方法

解决ByteBuddy运行时方法代理无法调用原方法的问题

你的核心问题是使用redefine时直接覆盖了原方法,导致无法调用原有业务逻辑。要实现前置条件判断+可选执行原方法的需求,推荐使用ByteBuddy的rebase模式(保留原方法字节码),或者更轻量高效的Advice机制,以下是具体实现方案:

方案一:Rebase模式+MethodDelegation

rebase会将原方法重命名为一个合成方法(如bar$original)并保留字节码,拦截器可通过@SuperCall注解调用原方法。

修改后代码

ByteBuddyAgent.install();
new ByteBuddy()
  .rebase(Foo.class) // 替换redefine为rebase
  .method(named("bar").and(takesArguments(String.class, float.class, Integer.class)))
  .intercept(MethodDelegation.to(Interceptor.class))
  .make()
  .load(Foo.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());

public class Interceptor {
   @RuntimeType
   public static void intercept(
       @AllArguments Object[] allArguments,
       @SuperCall Runnable superCall // 无返回值方法用Runnable接收原方法引用
   ) {
     // 自定义条件判断逻辑
     boolean shouldCallOriginal = true;
     if (shouldCallOriginal) {
       superCall.run(); // 执行原方法
     }
     System.out.println("Intercepted");
   }
}

若原方法有返回值,将@SuperCall Runnable替换为@SuperCall Callable<Object>,调用call()即可获取返回值。

方案二:Advice机制(性能更优)

Advice是直接修改目标方法字节码的轻量方案,无需方法委托,适合简单的前置判断场景。

实现代码

ByteBuddyAgent.install();
new ByteBuddy()
  .redefine(Foo.class) // 此处可复用redefine,Advice是直接插入代码而非替换方法
  .method(named("bar").and(takesArguments(String.class, float.class, Integer.class)))
  .intercept(Advice.to(BarAdvice.class))
  .make()
  .load(Foo.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());

public class BarAdvice {
   @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class) // 返回true时跳过原方法
   public static boolean before(
       @Advice.AllArguments Object[] args
   ) {
     // 示例条件:第一个参数为"skip"时跳过原方法
     boolean skipOriginal = args[0].equals("skip");
     System.out.println("Intercepted before method execution");
     return skipOriginal;
   }
}

@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)的逻辑是:若before方法返回true(boolean默认值为false,非默认值即触发跳过),则不执行原方法;返回false则正常执行原方法。

注意事项

  • 插件环境下需确保目标类Foo在你的插件加载时未被实例化(你提到可控制加载顺序,此条件可满足)。
  • 若目标类已加载,必须通过ClassReloadingStrategy.fromInstalledAgent()完成热重载,你的代码已正确调用ByteBuddyAgent.install()初始化代理。
  • 针对有返回值的方法,可通过@Advice.OnMethodExit结合@Advice.Return处理返回值逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 22:20:23