快速访问呼叫者信息

Ian*_*Ian 2 java performance aspectj stack-trace

我正在研究一个方面方面,需要知道它从哪里调用.目前我正在使用

new Throwable().getStackTrace();
Run Code Online (Sandbox Code Playgroud)

访问此信息,但每个方面需要几百微秒才能运行.

我看过SecurityManager,但似乎只能得到我的类名.

还有其他我错过的选择吗?

更新

JMH基准测试结果在我对@ apangin答案的评论中提到:

Benchmark                       Mode  Cnt      Score    Error  Units
MyBenchmark.javalangaccess13i   avgt  100   2025.865 ±  8.133  ns/op
MyBenchmark.javalangaccess2i    avgt  100   2648.598 ± 24.369  ns/op  
MyBenchmark.throwable1          avgt  100  12706.978 ± 84.651  ns/op
Run Code Online (Sandbox Code Playgroud)

基准代码:

@Benchmark
public StackTraceElement[] throwable1() {
    return new Throwable().getStackTrace();
}

@SuppressWarnings("restriction")
@Benchmark
public static StackTraceElement javalangaccess2i() {
    Exception e = new Exception();
    return sun.misc.SharedSecrets.getJavaLangAccess().getStackTraceElement(e, 2);
}

@SuppressWarnings("restriction")
@Benchmark
public static StackTraceElement javalangaccess13i() {
    Exception e = new Exception();
    return sun.misc.SharedSecrets.getJavaLangAccess().getStackTraceElement(e, 13);
}
Run Code Online (Sandbox Code Playgroud)

在戴尔XPS13 9343(i5-5200U @ 2.2GHz)上的Windows 10,JDK 1.8.0_112下运行测试

apa*_*gin 5

不幸的是,Throwable.getStackTrace()似乎是在纯Java 8中获取调用者帧的唯一可行选项.

但是,有一个JDK特定的技巧来访问一个选定的堆栈帧.
它使用非标准sun.misc.SharedSecretsAPI.

public static StackTraceElement getCaller() {
    Exception e = new Exception();
    return sun.misc.SharedSecrets.getJavaLangAccess().getStackTraceElement(e, 2);
}
Run Code Online (Sandbox Code Playgroud)

这里2是所需帧的索引.

这在最新的JDK 8之前工作正常,但在JDK 9中无法访问私有API.一个好消息是Java 9将具有新的标准Stack-Walking API.以下是如何在Java 9中执行相同操作.

public static StackWalker.StackFrame getCaller() {
    return StackWalker.getInstance(Collections.emptySet(), 3)
            .walk(s -> s.skip(2).findFirst())
            .orElse(null);
}
Run Code Online (Sandbox Code Playgroud)

另一种选择,适用于较旧版本和较新版本的Java,是JVMTI GetStackTrace函数.它需要链接本机代码.