字節碼實戰--手寫一個btrace 頂 原 薦

簡易的btrace需求

偶現的方法執行慢,我們是可以用jstack捕捉到的,但是慢到什麼地步卻是不一定知道的,現在就需要在不重啓應用的情況下,獲取方法執行的時間。

需求特點

  1. 應用不重啓
  2. 獲取方法執行時間

技術選型

想要打印出時間,起碼想到的是aop的方式。常規的方法是必須重啓應用才能加的,典型的就是spring的aop,如果允許修改代碼的話可以使用動態代理,或者自己寫死到代碼裏。

操作方案

動態代理或者寫死到代碼

這種情況對代碼的入侵太高了,如果要去掉這個功能,修改代碼也是很麻煩的。

spring aop

這個需要依賴spring框架來做。可以不修改代碼,但是不能做到動態生效。

javaagent

javaagent在1.6之後可以使用遠程attach的方式,進行類的重新轉化。這個是滿足需求的。這個不瞭解的話可以去網上查查看。

字節碼增強技術

方式選擇好以後,那麼關鍵點就是如何選擇修改字節碼的框架。

javassist

javassist是相對好用的,不過他想要在一個方法前後加代碼,是通過方法包裝來的,就是命名一個新的方法名和現在執行的方法名一樣,然後把舊的方法重新命名。流程如下: 轉化前:

 public void hello(){
        int a=0;
}

轉化後

public void hello(){
    xxx
    helloxx();
    xxx
}

 public void helloxx(){
        int a=0;
}

這種情況是transform的做法,但是retransform有不能新增方法的限制。jdk的文檔描述如下

The retransformation must not add, remove or rename fields or methods, change the signatures of methods, or change inheritance.

asm

asmapi操作比較麻煩。但是可以直接修改方法體的內容。 轉化前:

 public void hello(){
        int a=0;
}

轉化後:

 public void hello(){
        xxx
        int a=0;
        xxx
}

asm的做法也有兩種方式,一種是增加方法調用,然後把傳遞的值保存在threadlocal裏,另外一種就是把所有的內容寫到方法裏中。這兩種都可以滿足需求,第一種實現方式還簡單一些,不用新增本地變量。

實現方式

修改字節碼的代碼比較枯燥,所有直接附上代碼地址,此次使用的是asm增加方法局部變量的方式做的,這樣的demo網上博客沒有,asm的手冊中也沒有這樣的例子,如果有興趣的可以去看看 https://github.com/xpbob/lightTrace

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章