微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Java 8中获取调用方方法的有效方法?

如何解决Java 8中获取调用方方法的有效方法?

这就是我要实现的:如果有一个方法a()调用方法b(),我想知道是谁调用方法b()

public void a(){
  b();//but it is not necessarily in the same class
}

public void b(){
  String method = getCallerMethod();//returns 'a'
}

现在,这可以使用StackWalker API在Java 9+中有效地实现。在Java 8中,我可以使用Thread.currentThread().getStackTrace()new Exception().getStackTrace(),但是这两种方法都非常慢。我不需要整个堆栈跟踪,只需要堆栈跟踪中的前一帧,只需要该帧中方法名称(可能还需要类名)即可。

有没有办法在Java 8中有效地实现这一目标?

解决方法

  1. 在JDK 8中,有一个内部未公开的API,该API提供对单个堆栈跟踪元素的访问,而无需解码完整的堆栈跟踪:

    SharedSecrets.getJavaLangAccess().getStackTraceDepth(e)
    SharedSecrets.getJavaLangAccess().getStackTraceElement(e,index)
    

    它有助于避免解码堆栈跟踪的大量费用,但仍需要收集整个跟踪。有关详细信息,请参见this answer

  2. JVM TI GetStackTrace函数是更快的方法。其start_depthmax_frame_count参数仅允许获取堆栈跟踪的选定部分。

    这种方法的缺点是它需要一个本机库。

    example使用GetStackTrace几乎可以满足您的需要:StackFrame.getLocation(depth)方法仅返回给定深度的一个堆栈帧。

  3. 在仅需要调用者类的情况下(没有确切的方法),快速,标准和可移植的解决方案就是

    MethodHandles.lookup().lookupClass()
    
  4. 最后,如果仅需要调用方方法,则另一种解决方案是使用Bytecode Instrumentation查找调用方法invoke*的所有a字节码,并将其重写为调用方法a_with_caller(String callerMethod),其中callerMethod参数是一个检测时间常数,从所检测的方法派生。

,

您可以创建一个Exception并使用fillInStacktrace(),然后使用printStacktrace()并粘贴结果。

这可能不是很有效,但是我不明白为什么仅用于调试。

例如(我不在电脑上,所以我没有尝试编译它):

try (StringWriter wr = new StringWriter(); 
     PrintWriter pw = new PrintWriter(wr)) {
    new Exception().fillInStacktrace().printStacktrace(pw);
    try (Scanner sc = new Scanner(wr.toString())) {
        int atFound = 0;
        while (sc.hasNextLine()) {
            String line = sc.nextLine();
            if (line.contains("at")) {
                atFound++;
            } 
            if (atFound == 2) {
                // this should be the caller,first one is this method
            } 
        } 
   } 
} 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。