欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java獲取調用當前方法的類名或方法名(棧堆信息)的四種方式舉例

 更新時間:2024年09月01日 09:18:46   作者:星月昭銘  
在Java編程中我們經常需要在運行時獲取當前執(zhí)行的方法名稱,這在日志記錄、性能監(jiān)控、調試等方面非常有用,這篇文章主要給大家介紹了關于Java獲取調用當前方法的類名或方法名(棧堆信息)的四種方式,需要的朋友可以參考下

前言

在java代碼中,是可以在運行時通過某種方式獲取到當前方法被誰調用了(調用鏈路)。目前我所知道的有四種方式(通過Thread、Throwable、SecurityManager獲?。旅嬷饌€列出,附有代碼和截圖。

Thread.getAllStackTraces()方式

Thread.getAllStackTraces()可以獲取所有線程的棧堆跟蹤信息,返回值是Map<Thread, StackTraceElement[]>類型,可以通過Thread.currentThread()拿到當前Thread對象,從map集合中獲取棧堆跟蹤信息。StackTraceElement對象可以拿到調用者的類名、Class對象、調用的代碼所在行數等。

代碼如下:

public class A {
    public static void main(String[] args) {
        B.print();
    }
}

class B {
    public static void print() {
        System.out.println("調用B#print");
        C.print();
    }
}

class C {
    public static void print() {
        System.out.println("調用C#print");
        // 獲取所有線程的棧堆跟蹤集合
        Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces();
        // 去map集合里面拿當前線程的棧堆跟蹤信息數組
        StackTraceElement[] stackTraceElements = allStackTraces.get(Thread.currentThread());
        System.out.println(Arrays.toString(stackTraceElements));
    }
}

可以看到,下標為4的StackTraceElement對象就是我們的main方法,之所以出現了下標0、1非自定義類的棧堆信息是因為調用了Thread.getAllStackTraces()方法,方法以及方法內部也執(zhí)行了其他代碼。

Thread.currentThread().getStackTrace()方式

通過Thread.currentThread()拿到當前的線程,再通過Thread對象的getStackTrace()方法獲取線程的棧堆跟蹤信息,getStackTrace()非static方法,所以要先拿到Thread對象。第一種和第二種方式實際上都是調用了private native static StackTraceElement[][] dumpThreads(Thread[] threads)本地方法來獲取。這兩種方式獲取的話,棧堆跟蹤信息數組里面都有非自定義類的調用信息(看下標0)。

代碼如下:

public class A {
    public static void main(String[] args) {
        B.print();
        System.out.println(Arrays.toString(Thread.currentThread().getStackTrace()));
    }
}

class B {
    public static void print() {
        System.out.println("調用B#print");
        C.print();
    }
}

class C {
    public static void print() {
        // 獲取當前線程,再獲取棧堆跟蹤數組
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        System.out.println(Arrays.toString(stackTrace));
    }
}

new RuntimeException().getStackTrace()方式

實際上,只要是Throwable的子類包括他自身都可以,內部也是調用了一個本地方法來獲取的棧堆信息。SpringApplication類中的deduceMainApplicationClass()方法就是通過這種方式來拿主類的Class對象。拿到了之后就可以通過for循環(huán)整個數組通過匹配方法名或者類型來拿想要信息了,或者直接通過整個數組拿到整個調用鏈路。

代碼如下:

public class A {
    public static void main(String[] args) {
        B.print();
    }
}

class B {
    public static void print() {
        System.out.println("調用B#print");
        C.print();
    }
}

class C {
    public static void print() {
        StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
        System.out.println(Arrays.toString(stackTrace));
    }
}

SecurityManager方式(這種可以拿到類信息,但是拿不到棧堆信息)

SecurityManager中有一個getClassContext()方法,這個方法可以獲取到調用當前方法的Class信息,返回的類型是一個Class數組,和前面幾種不同的是,這種方式沒法獲取代碼行數、調用的方法等(Class對象大家應該很熟悉了,能拿到哪種信息應該都知道)。

由于getClassContext方法是非static的,所以要通過對象的方式調用,但是不能通過new SecurityManager()的對象來獲取,因為這個方法是一個protected方法。protected native Class[] getClassContext()。所以需要自定義一個類,繼承SecurityManager類,然后重寫getClassContext方法,這樣我們就能在這個類中使用這個方法了。

這種方式在slf4j中Util#getCallingClass()用到了

代碼如下:

public class A {
    public static void main(String[] args) {
        B.print();
    }
}

class B {
    public static void print() {
        System.out.println("調用B#print");
        C.print();
    }
}

class C {

    public static void print() {
        // 獲取一個安全管理器對象
        ClassContextSecurityManager securityManager = getSecurityManager();
        if (securityManager != null) {
            System.out.println(Arrays.toString(securityManager.getClassContext()));
        }
    }

    static ClassContextSecurityManager getSecurityManager() {
        try {
            return new ClassContextSecurityManager();
        } catch (Throwable throwable) {
            return null;
        }
    }

    /**
     * 自定義的安全管理器,繼承java.lang.SecurityManager類
     */
    private static final class ClassContextSecurityManager extends SecurityManager {
    	/**
    	 * 重寫getClassContext方法,不然方法在SecurityManager中又被protected修飾,其他類還是調用不了
    	 */
    	@Override
        protected Class<?>[] getClassContext() {
            return super.getClassContext();
        }
    }
}

總結 

到此這篇關于Java獲取調用當前方法的類名或方法名(棧堆信息)的四種方式的文章就介紹到這了,更多相關Java獲取調用當前方法類名或方法名內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Logback MDCAdapter日志跟蹤及自定義效果源碼解讀

    Logback MDCAdapter日志跟蹤及自定義效果源碼解讀

    這篇文章主要為大家介紹了Logback MDCAdapter日志跟蹤及自定義效果源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-11-11
  • Java實現FIFO功能的完整代碼實踐

    Java實現FIFO功能的完整代碼實踐

    在軟件開發(fā)中,隊列(Queue)是一種常見的數據結構,其特點是先進先出(FIFO,First In First Out),FIFO 隊列在生產者-消費者模型、任務調度、緩沖區(qū)管理等場景中具有廣泛的應用,本文給大家介紹了Java實現FIFO功能的完整代碼實踐,需要的朋友可以參考下
    2025-03-03
  • SpringCloud中Gateway的使用教程詳解

    SpringCloud中Gateway的使用教程詳解

    SpringCloud?Gateway是Spring體系內的一個全新項目,它旨在為微服務架構提供一種簡單有效的統(tǒng)一的API路由管理方式。本文就來為大家詳細講講Gateway的使用教程,需要的可以參考一下
    2022-08-08
  • spring security環(huán)境搭建

    spring security環(huán)境搭建

    本文通過代碼給大家介紹了spring security環(huán)境搭建的詳細教程,非常不錯,具有參考借鑒價值,需要的朋友參考下吧
    2017-09-09
  • spring retry 配置及使用教程

    spring retry 配置及使用教程

    這篇文章主要介紹了spring retry 配置及使用教程,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2024-01-01
  • java自定義jar包讓jmeter使用的方法

    java自定義jar包讓jmeter使用的方法

    在本篇文章里小編給大家整理了一篇關于java自定義jar包讓jmeter使用的方法以及實例代碼,需要的朋友們參考下。
    2019-10-10
  • Java 實戰(zhàn)項目錘煉之在線美食網站系統(tǒng)的實現流程

    Java 實戰(zhàn)項目錘煉之在線美食網站系統(tǒng)的實現流程

    讀萬卷書不如行萬里路,只學書上的理論是遠遠不夠的,只有在實戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+SSM+jsp+mysql+maven實現一個在線美食網站系統(tǒng),大家可以在過程中查缺補漏,提升水平
    2021-11-11
  • 深入理解Java的接口與抽象類

    深入理解Java的接口與抽象類

    本文主要介紹java 的接口和抽象類,對接口和抽象類進行介紹對比,深入理解,有需要的小伙伴可以參考下
    2016-07-07
  • 淺談Spring事務傳播行為實戰(zhàn)

    淺談Spring事務傳播行為實戰(zhàn)

    這篇文章主要介紹了淺談Spring事務傳播行為實戰(zhàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-09-09
  • SpringBoot 二維碼生成base64并上傳OSS的實現示例

    SpringBoot 二維碼生成base64并上傳OSS的實現示例

    本文主要介紹了SpringBoot 二維碼生成base64并上傳OSS的實現示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-05-05

最新評論