ByteBuddy Agent问题:HttpClient.send的Advice未调用Transport.send
问题:ByteBuddy开发Java Agent时调用外部静态方法无输出,内联日志正常
我用ByteBuddy开发Java Agent,目标是统计java.net.http.HttpClient类send方法的执行耗时,但遇到异常:Advice类的exit方法中调用Transport.send()时没有任何输出,若将日志语句直接内联到exit方法则可正常执行。
相关代码
premain方法
public static void premain(String arguments, Instrumentation instrumentation) { new AgentBuilder.Default() .ignore(ElementMatchers.none()) .with(Listener.StreamWriting.toSystemOut().withErrorsOnly()) .type(hasSuperType(named("java.net.http.HttpClient"))) .transform((builder, typeDescription, classLoader, module, protectionDomain) -> { return builder .visit(Advice.to(SendAdvice.class) .on(hasMethodName("send") .and(returns(named("java.net.http.HttpResponse"))))); }) .asTerminalTransformation() .installOn(instrumentation); }
Transport类
public class Transport { public static void send() { System.out.println("hello static"); } }
SendAdvice类
class SendAdvice { @Advice.OnMethodEnter() public static long start() { return System.nanoTime(); } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void exit( @Advice.Enter long startTime) throws MalformedURLException { Transport.send(System.nanoTime() - startTime); } }
问题分析
- 方法签名不匹配:Advice的exit方法中调用
Transport.send(long),但Transport类中定义的是无参的send(),参数不匹配导致调用失败。加上suppress = Throwable.class后,异常被静默吞掉,无法看到报错信息。 - 类加载器隔离:Java Agent的类加载器与
HttpClient所属的Bootstrap类加载器可能存在隔离,导致Transport类无法被正确加载或访问,同样因为异常被抑制而无法察觉。 - 类型匹配不准确:
hasSuperType(named("java.net.http.HttpClient"))可能匹配到非目标子类,导致Advice没有正确织入到HttpClient的send方法上。
解决方案
- 修复方法签名:调整Transport类的send方法,使其接收long类型参数,匹配调用逻辑:
public class Transport { public static void send(long cost) { System.out.println("send方法执行耗时:" + cost + "纳秒"); } }
- 移除异常抑制,排查真实错误:暂时去掉
suppress = Throwable.class,或添加异常捕获日志,明确问题根源:
@Advice.OnMethodExit(onThrowable = Throwable.class) public static void exit(@Advice.Enter long startTime) throws MalformedURLException { try { Transport.send(System.nanoTime() - startTime); } catch (Throwable t) { t.printStackTrace(); } }
- 调整类型匹配规则:直接匹配
HttpClient类而非父类,确保Advice织入目标方法:
.type(named("java.net.http.HttpClient"))
- 确保类加载可见性:如果
Transport类无法被Bootstrap类加载器访问,可通过AgentBuilder配置将其加入Bootstrap类路径,或使用AgentBuilder.Default().with(AgentBuilder.TypeStrategy.Default.REDEFINE)确保类加载策略正确。
内容的提问来源于stack exchange,提问作者Daven
相关产品推荐
相关产品推荐

