3

我正在尝试使用 ByteBuddy 实现 Profiler。我目前正在努力有效地创建我正在分析的方法的正确签名。

这是我当前实现的要点:https ://gist.github.com/felixbarny/e0c64819c59368a28200

ProfilingInterceptor.profile 方法有两种实现。每个人都有自己的缺陷。

第一个@Origin String signature用作签名。这是非常有效的,因为 ByteBuddy 似乎缓存了它。问题是,我对签名的格式不满意。例如method2(I)I.

在第二个实现中,我注入@Origin(cacheMethod = true) Method method并手动构建了一个更好看的签名:int org.stagemonitor.benchmark.profiler.ClassJavassistProfiled.method2(int). 明显的问题是每次调用都会重新创建签名 - 不是高性能的(我的 jmh 基准测试说它慢了 4 倍)。

有没有办法缓存签名,例如为每个签名创建一个字符串常量?

提前致谢

4

1 回答 1

1

完成你想要的最简单的方法是实现你自己的注释并创建一个绑定。然后将任何此类String值添加到类的常量池中并从那里简单地返回。

您可以在 Byte Buddy 教程的底部找到创建自定义注释的示例。要实现自定义@Signature注释,您将执行以下操作:

enum SignatureBinder
    implements TargetMethodAnnotationDrivenBinder.ParameterBinder<StringValue> {

  INSTANCE; // singleton

  @Override
  public Class<Signature> getHandledType() {
    return Signature.class;
  }

  @Override
  public MethodDelegationBinder.ParameterBinding<?> bind(AnnotationDescription.Loaded<StringValue> annotation,
      MethodDescription source,
      ParameterDescription target,
      Instrumentation.Target instrumentationTarget,
      Assigner assigner) {
    if (!target.getTypeDescription().represents(String.class)) {
      throw new IllegalStateException(target + " makes illegal use of @Signature");
    }
    StackManipulation constant = new TextConstant("<signature goes here>");
    return new MethodDelegationBinder.ParameterBinding.Anonymous(constant);
  }
}

MethodDescription命名的对象source描述了被拦截的方法,并提供了一个类似于Method类的接口。然后,您将使用 注册此活页夹,MethodDelegation然后您可以在委托中使用注释。

附带说明:我会避免使用规范名称。这些名称可能有冲突,例如类

foo.Bar$Qux
foo.Bar.Qux

曾经是具有Bar内部类的类Qux和曾经是具有类的包具有Qux相同的名称。我知道这不太可能,但你永远不知道用户代码会是什么样子。

于 2015-04-03T08:21:05.123 回答