當我們在記錄日志時,每個類中會定義一個日志對象,然后利用這個對象去寫日志,那么我們在處理日志時,如何能才能記錄日志對象所在的類、方法和行號呢?log4j中已經實現了該功能,那么它是怎么實現的呢?
其實我們可以這樣,在要寫日志的代碼時獲得當前的線程信息,這樣我們就可以獲得上個線程的信息了(即對象寫日志所在類的信息)。
先看以下列子。
新建Location類和Test類:
Location:
public class Location { public void getInfo(){ String location=""; StackTraceElement[] stacks = Thread.currentThread().getStackTrace(); location = "類名:"+stacks[2].getClassName() + "\n函數名:" + stacks[2].getMethodName() + "\n文件名:" + stacks[2].getFileName() + "\n行號:" + stacks[2].getLineNumber() + ""; System.out.println(location); } }
Test:
public class Test { public static void main(String[] args) { Location l = new Location(); l.getInfo(); } }
執行Test中的main函數,得到以下結果:
類名:thread.Test 函數名:main 文件名:Test.java 行號:10
是不是輸出了Test類中調用的信息呢?那么有很多人就問了,為什么location類中調用的是stacts[2]而不是stacts[0]或其他的呢?
針對這個問題,我們可以將stacts數組里面的東西遍歷輸出一下就知道了:
StackTraceElement[] stacks = Thread.currentThread().getStackTrace(); for(int i=0;i<stacks.length;i++){ location = i+" at "+stacks[i].getClassName() + "." + stacks[i].getMethodName() + "(" + stacks[i].getFileName() + ":" + stacks[i].getLineNumber() + ")"; System.out.println(location); }
再次執行,輸出結果如下:
0 at java.lang.Thread.getStackTrace(Thread.java:1436) 1 at thread.Location.getInfo(Location.java:6) 2 at thread.Test.main(Test.java:7)
那么這就好理解了,線程是以棧形式存放的,
分析一下StackTraceElement[] stacks = Thread.currentThread().getStackTrace();
此代碼中會創建2個線程,調用Thread.currentThread().getStackTrace()時底層會創建一個線程,我們調用它也會創建一個線程,然后test調用getInfo函數時會創建一個線程,這樣總共就三個線程了,程序執行順序是先test類中調用getInfo方法,然后getInfo方法中調用StackTraceElement[] stacks = Thread.currentThread().getStackTrace();調用StackTraceElement[] stacks = Thread.currentThread().getStackTrace();時底層還會創建一個線程,根據棧的原理先進后出規則,他們的排隊順序就是上面輸出的結果了。