Byte Buddy使用.andThen时返回值丢失,如何保留原方法返回值?
问题分析与解决方案
你的问题出在andThen(MethodCall.run(new CloseConnection()))的用法上:当链式调用andThen时,Byte Buddy会将整个拦截逻辑的返回值设置为最后一个操作的结果。而MethodCall.run(new CloseConnection())执行的是Runnable的run()方法(返回void),这就导致原proxyClient方法的返回值被覆盖丢弃了。
要在保留原方法返回值的同时,在方法执行后添加额外逻辑,有两种更合适的方式:
方式一:使用Byte Buddy Advice(推荐)
Advice是Byte Buddy中处理方法拦截的轻量且灵活的方式,通过注解可以轻松在方法执行前后插入逻辑,且自动保留原返回值:
T proxyClient = JAXRSClientFactory.fromClient(client, classType, true); this.configureHttpConduit(conduit, invocationTimeout); Class<?> buddy = new ByteBuddy() .subclass(classType) .method(ElementMatchers.isAnnotatedWith(Path.class)) .intercept(MethodDelegation.to(proxyClient).andThen(Advice.to(CloseConnectionAdvice.class))) .make() .load(this.getClass().getClassLoader(), Default.INJECTION) .getLoaded(); return (T) buddy.newInstance(); // 定义Advice类 static class CloseConnectionAdvice { @Advice.OnMethodExit static void afterMethod() { System.out.println("close connection called"); } }
这里的@Advice.OnMethodExit注解会确保代码在原方法执行完成后运行,无论原方法是否有返回值,都不会影响其返回结果。
方式二:调整MethodDelegation的链式调用
如果你想继续使用MethodDelegation和andThen,需要确保最后一个操作返回原方法的返回值。可以通过Return.of(...)来显式返回原返回值:
T proxyClient = JAXRSClientFactory.fromClient(client, classType, true); this.configureHttpConduit(conduit, invocationTimeout); Class<?> buddy = new ByteBuddy() .subclass(classType) .method(ElementMatchers.isAnnotatedWith(Path.class)) .intercept(MethodDelegation.to(proxyClient) .andThen(MethodCall.run(new CloseConnection())) .andThen(Return.ofValue(ArgumentStack.lastValue()))) .make() .load(this.getClass().getClassLoader(), Default.INJECTION) .getLoaded(); return (T) buddy.newInstance(); static class CloseConnection implements Runnable { @Override public void run() { System.out.println("close connection called"); } }
ArgumentStack.lastValue()会获取原方法执行后的返回值,再通过Return.ofValue将其作为整个拦截逻辑的返回值,这样就不会丢失原返回值了。
额外说明
相比第二种方式,Advice的写法更清晰,性能也更优(因为它是直接修改字节码,而非通过委托链),更推荐在这种场景下使用。
内容的提问来源于stack exchange,提问作者Ray Xie
相关产品推荐
相关产品推荐

