序
本文主要研究下
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}. * *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. * *
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. * *
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. * *
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
输出所有frames
@Test public void testGetAllFrames(){ Liststack = 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(){ OptionalfilteredResult = 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(){ ListframesAfterSkip = 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等方法。