首页 > 解决方案 > 在字节伙伴的 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 ms - 如果我有数千个电话,那就太多了)。

有没有办法在这一点上有效地让调用者(也许是一些字节好友的技巧)?

PS我的经纪人:

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();
    }

}

环境:Java 8

标签: javareflectionbytecodebyte-buddyjavaagents

解决方案


字节码检测仅允许您生成您也可以自己编写的代码。对于您的情况,您需要创建一个我不推荐的相当侵入性的仪器:

  1. 检测您的目标方法以接受类型的新参数Class
  2. 检测每个调用者以提供他们的类型作为附加参数。

更好的解决方案肯定是 Holger 在评论中建议的。使用StackWalker,如果不可用,回退到sun.reflect.Reflection(我知道的所有 JVM 中都存在)。


推荐阅读