使用 Byte Buddy 创建自定义方法签名的高效方法
Performant way of creating a custom method signature with 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 倍)。
有没有办法缓存签名,例如为每个签名创建一个字符串常量?
提前致谢
实现您想要的最简单方法是实现您自己的注释并创建绑定。然后将任何此类 String
值添加到 class 的常量池并从那里返回。
您可以在 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);
}
}
名为 source
的 MethodDescription
对象描述了拦截的方法并提供了类似于 Method
class 的接口。然后,您将使用 MethodDelegation
注册此活页夹,然后您可以在代理中使用注释。
附带说明:我会避免使用规范名称。这些名称可能会相互冲突,例如classes
foo.Bar$Qux
foo.Bar.Qux
with Bar
曾经是 class 和内部 class Qux
并且曾经是 class Qux
的包裹同名。我知道这不太可能,但你永远不知道用户代码会是什么样子。
我正在尝试使用 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 倍)。
有没有办法缓存签名,例如为每个签名创建一个字符串常量?
提前致谢
实现您想要的最简单方法是实现您自己的注释并创建绑定。然后将任何此类 String
值添加到 class 的常量池并从那里返回。
您可以在 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);
}
}
名为 source
的 MethodDescription
对象描述了拦截的方法并提供了类似于 Method
class 的接口。然后,您将使用 MethodDelegation
注册此活页夹,然后您可以在代理中使用注释。
附带说明:我会避免使用规范名称。这些名称可能会相互冲突,例如classes
foo.Bar$Qux
foo.Bar.Qux
with Bar
曾经是 class 和内部 class Qux
并且曾经是 class Qux
的包裹同名。我知道这不太可能,但你永远不知道用户代码会是什么样子。