【问题标题】:How to determine where method was called如何确定调用方法的位置
【发布时间】:2016-09-29 08:56:19
【问题描述】:

我提供了一个 API,并且需要知道调用 API 的方法的位置。我可以使用反射或线程堆栈跟踪,但这会包含大量运行时成本。

我不需要确切的类名,每次调用一个唯一的引用就足够了。在 C 语言中,我通常会使用预处理器自动将 __FILE____LINE__ 添加到方法调用中。

Java 中是否有一种方法(除了代码生成)可以以低运行时成本获得唯一的调用者标识?

【问题讨论】:

  • 只是想知道:您打算在这里解决什么问题?
  • 可以看看 AspectJ 并在调用您的 API 时设置一个连接点?
  • @matthelliwell “除了代码生成”消除了 AspectJ。
  • 我对AspectJ不够熟悉:我不是反对字节码生成,而是反对源码生成

标签: java stack-trace


【解决方案1】:

一种解决方案是使用缓存的 Throwable 并传入。

class StackPoint {
    Throwable stack;
    public Throwable getStack() {
        if (stack == null)
            stack = new Throwable();
        return stack;
    }
}

public void methodToCall(StackPoint sp) {
    Throwable t = sp.getStack();

}


static final StackPoint one = new StackPoint();

methodToCall(one); // Have to remember to give each line a different StackPoint.

注意:如果调用这个调用者的方法改变了,你只记录第一个。


没有标准模式,如果您希望这种模式高效,调用者可能需要传递一个唯一的 ID。您可以做的最接近的是使用 lambda。

public void methodToCall(Runnable run) {
    Class id = run.getClass();

}

你可以这样称呼它

methodtoCall(()->{});

这将为每个被调用的地方创建一个不同的类,即使它在同一行出现多次。它不会产生垃圾,因为它每次都重用同一个对象。你可以用

来缩短它
void methodToCall(IntFunction fun) {

}

然后打电话

methodToCall(a->1);

【讨论】:

  • 但是指望 lambda 的身份是错误的,不是吗?
  • @ooxi 提供调用者代码,他们可以复制和粘贴而无需手动更改,这意味着他们不太可能弄乱它。
  • @MarkoTopolnik 将来可能会共享具有相同代码的 lambda,即使它们位于不同的位置,但这不是 Java 8 或 9 当前所做的。他们离开的时间越长,这种情况发生的可能性就越小。
  • 确实是务实的观点 :) 不过,他们对这一点非常认真。
  • @GhostCat 它在运行时创建类,这可能是一个问题,但在您的部署中不会。
【解决方案2】:

由于涉及异步,将调用拆分,并让 API 返回 ID。

Ticket callTicket = api.call(params);
Logger.getLogger(getClass().getName(), Level.FINE, callTicket);
Result result = callTicket.get();

上面返回的结果(同步)可能不是您的代码的情况。您的代码将在其他地方获得结果。但这也可能是票务系统。

【讨论】:

  • 但是如何在不检查堆栈跟踪的情况下确定是否应返回新票?
  • 每次调用也在同一类和同一行中,从 API 中抽取一张新票。以登录为例。在异步异常中,票证是已知的,可以在日志中搜索。当然是不同的方法和视角。
  • 我当然更喜欢你的解决方案,因为它不会用技术细节来切割客户的代码。尽管如此,我仍将@PeterLawrey 的答案保留为已接受的答案,因为它确实更直接地解决了问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-26
  • 1970-01-01
  • 2020-11-07
  • 1970-01-01
  • 1970-01-01
  • 2010-11-10
相关资源
最近更新 更多