使用Byte Buddy创建自定义方法签名的高效方法

时间:2015-04-02 14:18:08

标签: java bytecode byte-buddy

我试图用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倍)。

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

提前致谢

1 个答案:

答案 0 :(得分:1)

实现所需内容的最简单方法是实现自己的注释并创建绑定。然后将任何此类String值添加到类的常量池中,并从那里返回。

您可以在Byte Buddy教程的底部找到example for creating a custom annotation。要实现自定义@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的{​​{1}}对象描述了截获的方法,并提供了类似于source类的接口。然后,您可以使用Method注册此活页夹,然后您可以在删除剂中使用注释。

旁注:我会避免使用规范名称。这些名称可能有冲突,例如班级

MethodDelegation

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