從OpenJDK8到OpenJDK11 - StackWalker類

本文基於OpenJDK 11java

以前升級了JDK到OpenJDK11,把遇到的問題以及解決方案列一下。 每篇文章會以提出問題,思路說明,解決問題的思路去行文。 這篇文章是關於堆棧信息獲取的。app

遇到的問題 - 調用堆棧獲取

以前有作調用堆棧監控上報,某些僅採集調用類,某些須要採集調用方法,整體來講:在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);
}

這種方式能夠靈活地獲取調用類,不用一會兒讀取整個堆棧。可是缺點是:沒法查看調用方法,信息不夠詳細 2. 經過Thread.currentThread().getStackTrace():代理

StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();

這種方法獲取的信息很詳細,可是一會兒返回整個堆棧的調用,不夠方便。code

升級到OpenJDK11以後,sun.reflect.Reflection類沒有了。get

思路說明

經過在Java 9以後JDK自帶的工具jdeps來尋找可替代的類:it

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

顯示:io

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

看到建議使用java.lang.StackWalker 咱們考慮用這個類替換sun.reflect.Reflection監控

解決問題

StackWalker能夠靈活地查看每一幀調用。 初始化能夠指定選項:jdk

//通常這樣就足夠用了,能夠把每一個調用棧輸出
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);
相關文章
相關標籤/搜索