字節碼實戰--手寫一個btrace

簡易的btrace需求

偶現的方法執行慢,咱們是能夠用jstack捕捉到的,可是慢到什麼地步倒是不必定知道的,如今就須要在不重啓應用的狀況下,獲取方法執行的時間。java

需求特色

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

技術選型

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

操做方案

動態代理或者寫死到代碼

這種狀況對代碼的入侵過高了,若是要去掉這個功能,修改代碼也是很麻煩的。github

spring aop

這個須要依賴spring框架來作。能夠不修改代碼,可是不能作到動態生效。spring

javaagent

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

字節碼加強技術

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

javassist

javassist是相對好用的,不過他想要在一個方法先後加代碼,是經過方法包裝來的,就是命名一個新的方法名和如今執行的方法名同樣,而後把舊的方法從新命名。流程以下: 轉化前:代理

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

轉化後code

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

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

這種狀況是transform的作法,可是retransform有不能新增方法的限制。jdk的文檔描述以下orm

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

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

相關文章
相關標籤/搜索