前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java9系列(五)Stack-Walking API

java9系列(五)Stack-Walking API

作者头像
code4it
发布2018-09-17 15:58:44
6330
发布2018-09-17 15:58:44
举报
文章被收录于专栏:码匠的流水账码匠的流水账

本文主要研究下JEP 259: Stack-Walking API

StackWalker

java9新增这个类的目的是提供一个标准API用于访问当前线程栈,之前只有Throwable::getStackTrace、Thread::getStackTrace以及SecurityManager::getClassContext提供了方法可以获取线程栈。

StackWalker.Option

/Library/Java/JavaVirtualMachines/jdk-9.0.4.jdk/Contents/Home/lib/src.zip!/java.base/java/lang/StackWalker.java

代码语言:javascript
复制
    /**
     * Stack walker option to configure the {@linkplain StackFrame stack frame}
     * information obtained by a {@code StackWalker}.
     *
     * @since 9
     */
    public enum Option {
        /**
         * Retains {@code Class} object in {@code StackFrame}s
         * walked by this {@code StackWalker}.
         *
         * <p> A {@code StackWalker} configured with this option will support
         * {@link StackWalker#getCallerClass()} and
         * {@link StackFrame#getDeclaringClass() StackFrame.getDeclaringClass()}.
         */
        RETAIN_CLASS_REFERENCE,
        /**
         * Shows all reflection frames.
         *
         * <p>By default, reflection frames are hidden.  A {@code StackWalker}
         * configured with this {@code SHOW_REFLECT_FRAMES} option
         * will show all reflection frames that
         * include {@link java.lang.reflect.Method#invoke} and
         * {@link java.lang.reflect.Constructor#newInstance(Object...)}
         * and their reflection implementation classes.
         *
         * <p>The {@link #SHOW_HIDDEN_FRAMES} option can also be used to show all
         * reflection frames and it will also show other hidden frames that
         * are implementation-specific.
         *
         * @apiNote
         * This option includes the stack frames representing the invocation of
         * {@code Method} and {@code Constructor}.  Any utility methods that
         * are equivalent to calling {@code Method.invoke} or
         * {@code Constructor.newInstance} such as {@code Class.newInstance}
         * are not filtered or controlled by any stack walking option.
         */
        SHOW_REFLECT_FRAMES,
        /**
         * Shows all hidden frames.
         *
         * <p>A Java Virtual Machine implementation may hide implementation
         * specific frames in addition to {@linkplain #SHOW_REFLECT_FRAMES
         * reflection frames}. A {@code StackWalker} with this {@code SHOW_HIDDEN_FRAMES}
         * option will show all hidden frames (including reflection frames).
         */
        SHOW_HIDDEN_FRAMES;
    }

创建StackWalker的选项,可组合使用

  • RETAIN_CLASS_REFERENCE,可以使用StackWalker#getCallerClass(),StackFrame#getDeclaringClass(),StackFrame.getDeclaringClass()方法
  • SHOW_REFLECT_FRAMES,默认反射相关的frames是被隐藏的,使用这个选项可以开启
  • SHOW_HIDDEN_FRAMES,除了反射相关的frames外jvm还会隐藏其他一些实现相关的frame,使用这个选项可以将所有都输出

实例

使用Thread的getStackTrace

代码语言:javascript
复制
    @Test
    public void testPrintCurrnentStackTrace(){
        StackTraceElement[] stack = Thread.currentThread().getStackTrace();
        for (StackTraceElement element : stack){
            System.out.println(element);
        }
    }

输出

代码语言:javascript
复制
java.base/java.lang.Thread.getStackTrace(Thread.java:1654)
test.com.packt.lang.StackWalkingTest.testPrintCurrnentStackTrace(StackWalkingTest.java:20)
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.base/java.lang.reflect.Method.invoke(Method.java:564)
org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
org.junit.runners.ParentRunner.run(ParentRunner.java:363)
org.junit.runner.JUnitCore.run(JUnitCore.java:137)
com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

SHOW_REFLECT_FRAMES

代码语言:javascript
复制
    private void print(StackWalker stackWalker){
        stackWalker.forEach(stackFrame -> System.out.printf("%6d| %s -> %s %n",
                stackFrame.getLineNumber(),
                stackFrame.getClassName(),
                stackFrame.getMethodName()));
    }

    @Test
    public void testShowReflectFrames(){
        final StackWalker stackWalker =
                StackWalker.getInstance(Option.SHOW_REFLECT_FRAMES);
        print(stackWalker);
    }

输出

代码语言:javascript
复制
    19| test.com.packt.lang.StackWalkingTest -> print 
    43| test.com.packt.lang.StackWalkingTest -> testShowReflectFrames 
    -2| jdk.internal.reflect.NativeMethodAccessorImpl -> invoke0 
    62| jdk.internal.reflect.NativeMethodAccessorImpl -> invoke 
    43| jdk.internal.reflect.DelegatingMethodAccessorImpl -> invoke 
   564| java.lang.reflect.Method -> invoke 
    50| org.junit.runners.model.FrameworkMethod$1 -> runReflectiveCall 
    12| org.junit.internal.runners.model.ReflectiveCallable -> run 
    47| org.junit.runners.model.FrameworkMethod -> invokeExplosively 
    17| org.junit.internal.runners.statements.InvokeMethod -> evaluate 
   325| org.junit.runners.ParentRunner -> runLeaf 
    78| org.junit.runners.BlockJUnit4ClassRunner -> runChild 
    57| org.junit.runners.BlockJUnit4ClassRunner -> runChild 
   290| org.junit.runners.ParentRunner$3 -> run 
    71| org.junit.runners.ParentRunner$1 -> schedule 
   288| org.junit.runners.ParentRunner -> runChildren 
    58| org.junit.runners.ParentRunner -> access$000 
   268| org.junit.runners.ParentRunner$2 -> evaluate 
   363| org.junit.runners.ParentRunner -> run 
   137| org.junit.runner.JUnitCore -> run 
    68| com.intellij.junit4.JUnit4IdeaTestRunner -> startRunnerWithArgs 
    47| com.intellij.rt.execution.junit.IdeaTestRunner$Repeater -> startRunnerWithArgs 
   242| com.intellij.rt.execution.junit.JUnitStarter -> prepareStreamsAndStart 
    70| com.intellij.rt.execution.junit.JUnitStarter -> main

比默认的多输出了jdk.internal.reflect相关frames

输出所有frames

代码语言:javascript
复制
    @Test
    public void testGetAllFrames(){
        List<StackWalker.StackFrame> stack =
                StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).walk((s) -> s.collect(Collectors.toList()));
        System.out.println("All frames : \n" + stack.toString());
    }

输出

代码语言:javascript
复制
All frames : 
[test.com.packt.lang.StackWalkingTest.testGetAll(StackWalkingTest.java:54), org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50), org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12), org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47), org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17), org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325), org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78), org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57), org.junit.runners.ParentRunner$3.run(ParentRunner.java:290), org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71), org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288), org.junit.runners.ParentRunner.access$000(ParentRunner.java:58), org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268), org.junit.runners.ParentRunner.run(ParentRunner.java:363), org.junit.runner.JUnitCore.run(JUnitCore.java:137), com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68), com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47), com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242), com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)]

过滤指定class

代码语言:javascript
复制
    @Test
    public void testFilterByClass(){
        Optional<StackWalker.StackFrame> filteredResult = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).walk((s) ->
                s.filter(f -> StackWalkingTest.class.equals(f.getDeclaringClass())).findFirst()
        );
        System.out.println("filter by class : \n"+filteredResult.toString());
    }

输出

代码语言:javascript
复制
filter by class : 
Optional[test.com.packt.lang.StackWalkingTest.testFilterByClass(StackWalkingTest.java:62)]

skip

代码语言:javascript
复制
    @Test
    public void testSkip(){
        List<StackWalker.StackFrame> framesAfterSkip = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).walk((s) ->
                s.skip(2).collect(Collectors.toList()));
        System.out.println("frames after skip : \n"+framesAfterSkip.toString());
    }

输出

代码语言:javascript
复制
frames after skip : 
[org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12), org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47), org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17), org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325), org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78), org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57), org.junit.runners.ParentRunner$3.run(ParentRunner.java:290), org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71), org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288), org.junit.runners.ParentRunner.access$000(ParentRunner.java:58), org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268), org.junit.runners.ParentRunner.run(ParentRunner.java:363), org.junit.runner.JUnitCore.run(JUnitCore.java:137), com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68), com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47), com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242), com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)]

这里skip了前两行

小结

java9引进的StackWalker可以更方便地打印当前线程堆栈,并提供了相关filter,skip等方法。

doc

  • JDK 9 features
  • StackWalker
  • JEP 259: Stack-Walking API
  • Introduction to Java 9 StackWalking API
  • Java 9 - StackWalker API
  • JDK 9: An Introduction to StackWalker
  • Java 9 Will Change the Way You Traverse Stack Traces
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-03-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码匠的流水账 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • StackWalker
  • StackWalker.Option
  • 实例
    • 使用Thread的getStackTrace
      • SHOW_REFLECT_FRAMES
        • 输出所有frames
          • 过滤指定class
            • skip
            • 小结
            • doc
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档