首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >快速访问呼叫者信息

快速访问呼叫者信息
EN

Stack Overflow用户
提问于 2016-10-25 17:34:28
回答 2查看 694关注 0票数 2

我正在研究aspectj方面,它需要知道从哪里调用它。我现在用的是

代码语言:javascript
复制
new Throwable().getStackTrace();

要访问这些信息,每个方面都需要几百微秒才能运行。

我看过SecurityManager,但这似乎只能给我一个类名。

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

更新

我在评论@apangin的答复时提到了JMH的基准结果:

代码语言:javascript
复制
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

基准代码:

代码语言:javascript
复制
@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);
}

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-10-25 21:24:41

不幸的是,Throwable.getStackTrace()似乎是在纯Java8中获得调用方框架的唯一可行选择。

但是,有一个特定于JDK的技巧,即只访问一个选定的堆栈框架。

它使用非标准的sun.misc.SharedSecrets API.

代码语言:javascript
复制
public static StackTraceElement getCaller() {
    Exception e = new Exception();
    return sun.misc.SharedSecrets.getJavaLangAccess().getStackTraceElement(e, 2);
}

这里2是所需帧的索引。

这在最新的JDK 8之前运行良好,但是在JDK 9中不能访问私有API。好消息是Java9将有新的标准堆栈遍历API。下面是如何在Java 9中做同样的事情。

代码语言:javascript
复制
public static StackWalker.StackFrame getCaller() {
    return StackWalker.getInstance(Collections.emptySet(), 3)
            .walk(s -> s.skip(2).findFirst())
            .orElse(null);
}

替代选项是JVMTI GetStackTrace函数,它适用于较早版本和较新版本的Java。不过,它需要链接本地代码。

票数 5
EN

Stack Overflow用户

发布于 2016-11-05 12:03:11

你说的是AspectJ。因此,您不需要任何反射,而只需使用板载AspectJ方法,例如thisEnclosingJoinPointStaticPart.getSignature()call()切入点:

驱动程序应用程序:

代码语言:javascript
复制
package de.scrum_master.app;

public class Application {
    private static final long NUM_LOOPS = 1000 * 1000;

    public static void main(String[] args) {
        Application application = new Application();

        long startTime = System.nanoTime();
        for (long i = 0; i < NUM_LOOPS; i++)
            application.doSomething();
        System.out.printf(
            "%-40s  |  %8.3f ms%n",
            "AspectJ thisEnclosingJoinPointStaticPart",
            (System.nanoTime() - startTime) / 1.0e6
        );

        startTime = System.nanoTime();
        for (long i = 0; i < NUM_LOOPS; i++)
            application.doSomething2();
        System.out.printf(
            "%-40s  |  %8.3f ms%n",
            "Throwable.getStackTrace",
            (System.nanoTime() - startTime) / 1.0e6
        );

        startTime = System.nanoTime();
        for (long i = 0; i < NUM_LOOPS; i++)
            application.doSomething3();
        System.out.printf(
            "%-40s  |  %8.3f ms%n",
            "SharedSecrets.getJavaLangAccess",
            (System.nanoTime() - startTime) / 1.0e6
        );
    }

    public void doSomething() {}
    public void doSomething2() {}
    public void doSomething3() {}
}

方面:

代码语言:javascript
复制
package de.scrum_master.aspect;

import de.scrum_master.app.Application;
import sun.misc.SharedSecrets;

public aspect MyAspect {
    before() : call(* Application.doSomething()) {
        Object o = thisEnclosingJoinPointStaticPart.getSignature();
        //System.out.println(o);
    }

    before() : call(* Application.doSomething2()) {
        Object o = new Throwable().getStackTrace()[1];
        //System.out.println(o);
    }

    before() : call(* Application.doSomething3()) {
        Object o = SharedSecrets.getJavaLangAccess().getStackTraceElement(new Throwable(), 1);
        //System.out.println(o);
    }
}

控制台日志:

代码语言:javascript
复制
AspectJ thisEnclosingJoinPointStaticPart  |     7,246 ms
Throwable.getStackTrace                   |  1852,895 ms
SharedSecrets.getJavaLangAccess           |  1043,050 ms

如您所见,AspectJ比下一种基于反射的方法快约140倍。

顺便说一句,如果您取消了方面中的print语句的注释,您将看到以下三种类型的输出:

代码语言:javascript
复制
void de.scrum_master.app.Application.main(String[])
de.scrum_master.app.Application.main(Application.java:16)
de.scrum_master.app.Application.main(Application.java:21)

享受吧!

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40246227

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档