从OpenJDK8到OpenJDK11 - StackWalker类

简介: 从OpenJDK8到OpenJDK11 - StackWalker类
本文基于OpenJDK 11

之前升级了JDK到OpenJDK11,把遇到的问题以及解决方案列一下。 每篇文章会以提出问题,思路说明,解决问题的思路去行文。 这篇文章是关于堆栈信息获取的。


遇到的问题 - 调用堆栈获取


之前有做调用堆栈监控上报,某些仅采集调用类,某些需要采集调用方法,总体来说:在Java8中,我们可以这样去获取调用堆栈:

  1. 通过Reflection类:
private static void getCallStackClassNames() {
    StringBuffer sbStack = new StringBuffer();
    int i = 0;
    Class<?> caller = Reflection.getCallerClass(i++);
    do {
        sbStack.append(i + ".").append(caller.getName())
            .append("\n");
        caller = Reflection.getCallerClass(i++);
    } while (caller != null);
    LOGGER.info("{}", sbStack);
}

这种方式可以灵活地获取调用类,不用一下子读取整个堆栈。但是缺点是:无法查看调用方法,信息不够详细

  1. 通过Thread.currentThread().getStackTrace():
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();

这种方法获取的信息很详细,但是一下子返回整个堆栈的调用,不够方便。

升级到OpenJDK11之后,sun.reflect.Reflection类没有了。


思路说明


通过在Java 9之后JDK自带的工具jdeps来寻找可替代的类:

jdeps  --jdk-internals ./target/AppName.jar

显示:

...
JDK Internal API                         Suggested Replacement
----------------                         ---------------------
sun.reflect.Reflection                   Use java.lang.StackWalker @since 9

看到建议使用java.lang.StackWalker 我们考虑用这个类替换sun.reflect.Reflection


解决问题


StackWalker可以灵活地查看每一帧调用。 初始化可以指定选项:

//一般这样就足够用了,可以把每个调用栈输出
StackWalker walker = StackWalker.getInstance();

也可以指定初始化参数:

//这样对于调用:StackWalker#getCallerClass()和StackFrame#getDeclaringClass()不会报异常,默认初始化是不支持这两个方法的
StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);

如果你想看反射的调用栈,例如Spring动态代理反射,可以这么初始化:

StackWalker walker = StackWalker.getInstance(StackWalker.Option.SHOW_REFLECT_FRAMES);

如果你想看完整的调用栈没有隐藏任何的调用栈,可以这么初始化:

StackWalker walker = StackWalker.getInstance(StackWalker.Option.SHOW_HIDDEN_FRAMES);

之后应用,例如取第一个调用栈:

walker.walk(s -> s.limit(1).collect(Collectors.toList()));

将每一个输出:

walker.forEach(System.out::println);
相关文章
|
C++
编译OpenJDK11,必须使用VS 2017
编译OpenJDK11,必须使用VS 2017
93 0
编译OpenJDK11,必须使用VS 2017
|
Java Windows
使用VS2015编译OpenJDK8
使用VS2015编译OpenJDK8
112 0
从openjdk.java.net获取OpenJDK8源码并编译(amd64/aarch64/arm64)
从openjdk.java.net获取OpenJDK8源码并编译(amd64/aarch64/arm64)
346 0
OpenJDK8和OpenJDK8u的差异
OpenJDK8和OpenJDK8u的差异
358 0
编译OpenJDK12:可以用VS2010到VS2017
编译OpenJDK12:可以用VS2010到VS2017
80 0
|
Java
编译OpenJDK8:OpenJDK8与OpenJDK8u运行结果相差很大
编译OpenJDK8:OpenJDK8与OpenJDK8u运行结果相差很大
189 0
|
Java Linux 开发工具
Centos 安装Java JDK8
Centos 安装Java JDK8
369 0
Centos 安装Java JDK8
|
Java Shell 开发工具
【openJDK系列1】macos编译openJDK 8
【openJDK系列1】macos编译openJDK 8
248 0
【openJDK系列1】macos编译openJDK 8
|
XML Java API
OpenJDK8升级到OpenJDK11需要注意的修改与异常
OpenJDK8升级到OpenJDK11需要注意的修改与异常
OpenJDK8-u302-b03哪里去也?
OpenJDK8-u302-b03哪里去也?
124 0
OpenJDK8-u302-b03哪里去也?