在字节好友的MethodDelegation中高效get caller
Efficiently get caller in byte buddy's MethodDelegation
我正在尝试使用字节伙伴库在我的 java 代理中构建一个调用树。要向树中添加元素,我想使用方法委托。但是,为了确定谁是任何叶子的父级,我需要知道谁调用了该方法。
我不想使用:
sun.reflect.Reflection#getCallerClass(int)
因为它在 Java 8+ 中已弃用且不可用。
另外,我试过:
public class ThreadUtil {
public static StackTraceElement getCaller() {
Instant now = Instant.now();
StackTraceElement ste = Thread.currentThread().getStackTrace()[3];
String callerClass = ste.getClassName();
String callerMethod = ste.getMethodName();
Instant now2= Instant.now();
System.out.println(Duration.between(now, now2));
return ste;
}
}
但是,它非常慢(大约 1 毫秒 - 如果我有数千个调用,那就太慢了)。
这时候有没有什么办法可以高效的获取caller(可能是一些字节小伙伴的技巧)?
P.S。
我的经纪人:
private static void instrument(String agentOps, Instrumentation inst) {
System.out.println("Agent");
new AgentBuilder.Default().with(new Eager())
.ignore(ElementMatchers.nameContains("com.dvelopp.agenttest"))
.type((ElementMatchers.any()))
.transform((builder, typeDescription, classLoader, module) -> builder.method(ElementMatchers.any())
.intercept(MethodDelegation.to(Interceptor.class))).installOn(inst);
}
public static class Interceptor {
@RuntimeType
public static Object intercept(@SuperCall Callable<?> zuper, @Origin Method method,
@AllArguments Object[] args, @This(optional = true) Object me) throws Exception {
System.out.println("CURRENT: " + method.getDeclaringClass().getName());
System.out.println("CALLER: " + ThreadUtil.getCaller().getClassName());
return zuper.call();
}
}
环境:Java8
字节码检测只允许您生成您也可以自己编写的代码。对于您的情况,您需要创建一个我不推荐的相当侵入性的工具:
- 检测您的目标方法以接受类型为
Class
的新参数。
- 检测每个调用者以提供他们的类型作为附加参数。
更好的解决方案肯定是 Holger 在评论中提出的建议。使用 StackWalker
,如果不可用,则退回到 sun.reflect.Reflection
(我知道的所有 JVM 中都存在)。
我正在尝试使用字节伙伴库在我的 java 代理中构建一个调用树。要向树中添加元素,我想使用方法委托。但是,为了确定谁是任何叶子的父级,我需要知道谁调用了该方法。
我不想使用:
sun.reflect.Reflection#getCallerClass(int)
因为它在 Java 8+ 中已弃用且不可用。 另外,我试过:
public class ThreadUtil {
public static StackTraceElement getCaller() {
Instant now = Instant.now();
StackTraceElement ste = Thread.currentThread().getStackTrace()[3];
String callerClass = ste.getClassName();
String callerMethod = ste.getMethodName();
Instant now2= Instant.now();
System.out.println(Duration.between(now, now2));
return ste;
}
}
但是,它非常慢(大约 1 毫秒 - 如果我有数千个调用,那就太慢了)。
这时候有没有什么办法可以高效的获取caller(可能是一些字节小伙伴的技巧)?
P.S。 我的经纪人:
private static void instrument(String agentOps, Instrumentation inst) {
System.out.println("Agent");
new AgentBuilder.Default().with(new Eager())
.ignore(ElementMatchers.nameContains("com.dvelopp.agenttest"))
.type((ElementMatchers.any()))
.transform((builder, typeDescription, classLoader, module) -> builder.method(ElementMatchers.any())
.intercept(MethodDelegation.to(Interceptor.class))).installOn(inst);
}
public static class Interceptor {
@RuntimeType
public static Object intercept(@SuperCall Callable<?> zuper, @Origin Method method,
@AllArguments Object[] args, @This(optional = true) Object me) throws Exception {
System.out.println("CURRENT: " + method.getDeclaringClass().getName());
System.out.println("CALLER: " + ThreadUtil.getCaller().getClassName());
return zuper.call();
}
}
环境:Java8
字节码检测只允许您生成您也可以自己编写的代码。对于您的情况,您需要创建一个我不推荐的相当侵入性的工具:
- 检测您的目标方法以接受类型为
Class
的新参数。 - 检测每个调用者以提供他们的类型作为附加参数。
更好的解决方案肯定是 Holger 在评论中提出的建议。使用 StackWalker
,如果不可用,则退回到 sun.reflect.Reflection
(我知道的所有 JVM 中都存在)。