java9系列(五)Stack-Walking API

发布时间:2019-11-19 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了java9系列(五)Stack-Walking API脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

本文主要研究下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

    /**      * 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

    @test     public void testPrintCurrnentStackTrace(){         StackTraceElement[] stack = Thread.currentThread().getStackTrace();         for (StackTraceElement element : stack){             System.out.println(element);         }     }

输出

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

    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);     }

输出

    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
@H_863_406@输出所有frames
    @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());     }

输出

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

    @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());     }

输出

filter by class :  Optional[test.com.packt.lang.StackWalkingTest.testFilterByClass(StackWalkingTest.java:62)]

skip

    @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());     }

输出

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

脚本宝典总结

以上是脚本宝典为你收集整理的java9系列(五)Stack-Walking API全部内容,希望文章能够帮你解决java9系列(五)Stack-Walking API所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。