无法使用 ByteBuddy 代理转换 class

Cannot transform class with ByteBuddy Agent

我实际上正在用 ByteBuddy API 编写一个 Java 代理,我需要在其中监视一些方法。比方说我需要记录一个方法的执行时间。

这是我的代码:

    public class PerfAgents {

     public static void premain(String agentArgs, Instrumentation inst){
        LOGGER.info("[Agent] Loading classes ...");
        Class classToMonitor = getClassFromArgs(agentArgs);
        String methodToMonitor = getMethodFromArgs(agentArgs);
        installAgent(inst, classToMonitor, methodToMonitor);
    }

     private static void installAgent(Instrumentation instrumentation, Class<?> classToMonitor, String methodToMonitor) {
      new AgentBuilder.Default()
           .type(is(classToMonitor))
           .transform((builder, typeDescription, classLoader, module) ->
                {
                    LOGGER.info("Transforming {} for {}", method, classToMonitor.getSimpleName());
                    return builder.method(named(methodToMonitor))
                           .intercept(MethodDelegation.to(TimerInterceptor.class));
           }).installOn(instrumentation);
  }

}

TimerInterceptor 类似于 ByteBuddy 教程中的 LoggerInterceptor,我在其中使用了 @SuperCall 注释。

问题不在于我不确定 ByteBuddy 是否将转换应用于提供的 class 和方法。我可以看到代理正在我的应用程序中加载,但是当我执行我的监控方法时,没有任何反应。

这是我的 TimerInterceptor class :

static class TimerInterceptor {

    private static Logger LOGGER = LoggerFactory.getLogger(LogInterceptor.class);


    public static Object log(@SuperCall Callable<Object> callable) throws Exception {
        LocalTime start = LocalTime.now();
        Object called = callable.call();
        LocalTime end = LocalTime.now();
        Duration between = Duration.between(start, end);

        LOGGER.info("Execution time : {} ms", between.toMillis());
        return called;
    }
}

如有任何帮助,我们将不胜感激。

您未将 Byte Buddy 配置为重新转换已加载的 classes。您可以通过在代理生成器 DSL 中设置 .with(RetransformationStrategy.RETRANSFORM) 来实现。

如果您可以避免重新转换,即如果您只检测在执行代理时未加载的应用程序 classes,您可以跳过此步骤。相反,使用基于字符串的匹配器并且不加载 class。如果需要更丰富的描述,也可以使用一个TypePool.Default让字节好友解析class个文件而不加载classes.

要查看 Byte Buddy 在做什么,您可以注册一个 Listener.StreamWriting.toSystemOut(),其中所有发现的 classes 都会打印到控制台,包括任何潜在的错误。