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

