我试图用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倍)。
有没有办法缓存签名,例如为每个签名创建一个字符串常量?
提前致谢
答案 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
的包具有相同的名称。我知道这不太可能,但你永远不知道用户代码会是什么样子。