使用Throwable获得栈信息
AOP(Aspect Oriented Programming面向切面編程)可以很輕松的控制一個方法調(diào)用哪些類,也能夠控制哪些方法允許被調(diào)用,一般來說切面編程(比如AspectJ)只能控制到方法級別,不能實現(xiàn)代碼級別的植入(Weave),比如一個方法被類A的m1方法調(diào)用時返回1,在類B的m2方法調(diào)用時返回0(同參數(shù)的情況下),這就要求被調(diào)用者具有識別調(diào)用者的能力.在這種情況下,可以使用Throwable獲得棧信息,然后鑒別調(diào)用者并分別輸出,代碼如下:
1 public class Client { 2 public static void main(String[] args) { 3 Invoker.m1(); 4 Invoker.m2(); 5 } 6 7 } 8 9 class Foo { 10 public static boolean m() { 11 // 取得當(dāng)前棧信息 12 StackTraceElement[] sts = new Throwable().getStackTrace(); 13 // 檢查是否是m1方法調(diào)用 14 for (StackTraceElement st : sts) { 15 if (st.getMethodName().equals("m1")) { 16 return true; 17 } 18 } 19 return false; 20 } 21 } 22 23 class Invoker { 24 // 該方法打印出true 25 public static void m1() { 26 System.out.println(Foo.m()); 27 } 28 29 // 該方法打印出false 30 public static void m2() { 31 System.out.println(Foo.m()); 32 } 33 }Invoker類,兩個方法m1和m2都調(diào)用了Foo的m方法,都是無參調(diào)用,返回值卻不相同.這是因為Throwable類發(fā)揮效能了.
JVM在創(chuàng)建一個Throwable類及其子類時會把當(dāng)前線程的棧信息記錄下來,以便在輸出異常時準(zhǔn)確定位異常原因,看Throwable的源代碼...
public class Throwable implements Serializable {//出現(xiàn)異常的棧記錄private StackTraceElement[] stackTrace;//默認(rèn)的構(gòu)造函數(shù)public Throwable() {//記錄棧幀 fillInStackTrace();}//本地方法,抓取執(zhí)行時的棧信息public synchronized native Throwable fillInStackTrace() {} }出現(xiàn)異常時(或主動聲明一個Throwabke對象時),JVM會通過fillInStackTrace方法記錄下棧幀信息,然后生成一個Throwable對象,這樣我們就可以知道類間的調(diào)用順序,方法名稱以及當(dāng)前行號等了.
獲得棧信息可以對調(diào)用者進(jìn)行判斷,然后決定不同的輸出,比如上面的m1和m2方法,同樣是輸入?yún)?shù),同樣的調(diào)用方法,但是輸出卻不同,這看起來像一個Bug:方法m1電泳m方法是正常顯示,而方法m2調(diào)用卻返回錯誤數(shù)據(jù).
因此我們雖然可以依據(jù)調(diào)用者不同產(chǎn)生不同的邏輯,但這僅僅局限在對方法的廣泛認(rèn)知上.
更多的時候我們用m方法的變形體代碼如下:
1 public class Client { 2 public static void main(String[] args) { 3 Invoker.m1(); 4 Invoker.m2(); 5 } 6 7 } 8 9 class Foo { 10 public static boolean m() { 11 // 取得當(dāng)前棧信息 12 StackTraceElement[] sts = new Throwable().getStackTrace(); 13 // 檢查是否是m1方法調(diào)用 14 for (StackTraceElement st : sts) { 15 if (st.getMethodName().equals("m1")) { 16 return true; 17 } 18 } 19 throw new RuntimeException("除m1方法外,該方法不允許其他方法調(diào)用"); 20 } 21 } 22 23 class Invoker { 24 // 該方法打印出true 25 public static void m1() { 26 System.out.println(Foo.m()); 27 } 28 29 // 該方法打印出false 30 public static void m2() { 31 System.out.println(Foo.m()); 32 } 33 }只是把return false 替換成了一個運行期異常,除了m1方法外,其他方法調(diào)用都會產(chǎn)生異常.除了m1方法外,其他方法調(diào)用都會產(chǎn)生異常,該方法常用作離線注冊碼校驗,當(dāng)破解者試圖暴力破解時,由于主執(zhí)行者不善期望的值,因此會返回一個經(jīng)過包裝和混淆的異常信息,大大增加了破解的難度.
?
本文轉(zhuǎn)自SummerChill博客園博客,原文鏈接:http://www.cnblogs.com/DreamDrive/p/5622976.html,如需轉(zhuǎn)載請自行聯(lián)系原作者
總結(jié)
以上是生活随笔為你收集整理的使用Throwable获得栈信息的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【HIMI转载推荐之三】新手教程之如何向
- 下一篇: 正则表达式grep sed awk总结