Java Language
Stack-Walking API
Sök…
Introduktion
Före Java 9 var åtkomsten till trådstackramarna begränsad till en intern klass sun.reflect.Reflection
. Specifikt metoden sun.reflect.Reflection::getCallerClass
. Vissa bibliotek förlitar sig på den här metoden som avskrivs.
En alternativ standard-API tillhandahålls nu i JDK 9 via java.lang.StackWalker
klassen, och är utformad för att vara effektiv genom att tillåta lat tillträde till stackramar. Vissa applikationer kan använda detta API för att korsa exekveringsstacken och filtrera på klasser.
Skriv ut alla stapelramar för den aktuella tråden
Följande skriver ut alla stapelramar i den aktuella tråden:
1 package test;
2
3 import java.lang.StackWalker.StackFrame;
4 import java.lang.reflect.InvocationTargetException;
5 import java.lang.reflect.Method;
6 import java.util.List;
7 import java.util.stream.Collectors;
8
9 public class StackWalkerExample {
10
11 public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
12 Method fooMethod = FooHelper.class.getDeclaredMethod("foo", (Class<?>[])null);
13 fooMethod.invoke(null, (Object[]) null);
14 }
15 }
16
17 class FooHelper {
18 protected static void foo() {
19 BarHelper.bar();
20 }
21 }
22
23 class BarHelper {
24 protected static void bar() {
25 List<StackFrame> stack = StackWalker.getInstance()
26 .walk((s) -> s.collect(Collectors.toList()));
27 for(StackFrame frame : stack) {
28 System.out.println(frame.getClassName() + " " + frame.getLineNumber() + " " + frame.getMethodName());
29 }
30 }
31 }
Produktion:
test.BarHelper 26 bar
test.FooHelper 19 foo
test.StackWalkerExample 13 main
Skriv ut aktuell anropsklass
Följande skriver ut den aktuella anropsklassen. Notera att i detta fall StackWalker
måste skapas med alternativet RETAIN_CLASS_REFERENCE
, så att Class
instanser kvar i StackFrame
objekt. Annars skulle ett undantag inträffa.
public class StackWalkerExample {
public static void main(String[] args) {
FooHelper.foo();
}
}
class FooHelper {
protected static void foo() {
BarHelper.bar();
}
}
class BarHelper {
protected static void bar() {
System.out.println(StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE).getCallerClass());
}
}
Produktion:
class test.FooHelper
Visar reflektion och andra dolda ramar
Ett par andra alternativ tillåter stapelspår att inkludera implementerings- och / eller reflektionsramar. Detta kan vara användbart för felsökning. Vi kan till exempel lägga till alternativet SHOW_REFLECT_FRAMES
i StackWalker
instansen vid skapandet, så att ramarna för de reflekterande metoderna också skrivs ut:
package test;
import java.lang.StackWalker.Option;
import java.lang.StackWalker.StackFrame;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.stream.Collectors;
public class StackWalkerExample {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Method fooMethod = FooHelper.class.getDeclaredMethod("foo", (Class<?>[])null);
fooMethod.invoke(null, (Object[]) null);
}
}
class FooHelper {
protected static void foo() {
BarHelper.bar();
}
}
class BarHelper {
protected static void bar() {
// show reflection methods
List<StackFrame> stack = StackWalker.getInstance(Option.SHOW_REFLECT_FRAMES)
.walk((s) -> s.collect(Collectors.toList()));
for(StackFrame frame : stack) {
System.out.println(frame.getClassName() + " " + frame.getLineNumber() + " " + frame.getMethodName());
}
}
}
Produktion:
test.BarHelper 27 bar
test.FooHelper 20 foo
jdk.internal.reflect.NativeMethodAccessorImpl -2 invoke0
jdk.internal.reflect.NativeMethodAccessorImpl 62 invoke
jdk.internal.reflect.DelegatingMethodAccessorImpl 43 invoke
java.lang.reflect.Method 563 invoke
test.StackWalkerExample 14 main
Observera att radnummer för vissa reflektionsmetoder kanske inte är tillgängliga så StackFrame.getLineNumber()
kan returnera negativa värden.