當我們在記錄日志時,每個類中會定義一個日志對象,然后利用這個對象去寫日志,那么我們在處理日志時,如何能才能記錄日志對象所在的類、方法和行號呢?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();時底層還會創建一個線程,根據棧的原理先進后出規則,他們的排隊順序就是上面輸出的結果了。
