Java agent又叫做Java 探針,本文將從以下四個問題出發來深入淺出了解下Java agent
一、什么是java agent?
Java agent是在JDK1.5引入的,是一種可以動態修改Java字節碼的技術。java類編譯之后形成字節碼被JVM執行,JVM在執行這些字節碼之前獲取這些字節碼信息,並且對這些字節碼進行修改,來完成一些額外的功能,這種就是java agent技術。
二、java agent可以實現什么樣的功能?
1.java agent能夠在加載java字節碼之前進行攔截並對字節碼進行修改
2.在jvm運行期間修改已經加載的字節碼
通過以上兩種就可以實現在一些框架或是技術的采集點進行字節碼修改,可以對應用進行監控,或是對執行指定方法或是接口時額外添加操作(打印日志、打印方法執行時間、采集方法的入參和結果等)
三、java agent的實現原理?
了解java agent的實現原理就必須先了解java的類加載機制(還不了解的自行了解),這個是了解java agent的前提。
其次需要了解的是JVMTI以及JVMTIAgent,下面分別介紹下
3.1、JVMTI
JVMTI是JVM Tool Interface的縮寫,是JVM暴露出來給用戶擴展使用的接口集合,JVMTI是基於事件驅動的,JVM每執行一定的邏輯就會調用一些事件的回調接口,這些接口可以給用戶自行擴展來實現自己的邏輯
3.2、JVMTIAgent
JVMTIAgent是一個動態庫,利用JVMTI暴露出來的接口實現用戶自行的邏輯(eclipse、idea等工具等代碼調試就是通過這個實現的)
JVMTIAgent主要有三個方法,
Agent_OnLoad方法,如果agent在啟動時加載,就執行這個方法
Agent_OnAttach方法,如果agent不是在啟動的時候加載的,是我們先attach到目標線程上,然后對對應的目標進程發送load命令來加載agent,在加載過程中調用Agent_OnAttach函數
Agent_OnUnload方法,在agent做卸載掉時候調用
3.3、instrument agent
instrument agent實現了Agent_OnLoad方法和Agent_OnAttach方法,也就是即能在啟動的時候加載agent,也可以在運行期來加動態加載agent,運行期動態加載agent依賴JVM的attach機制實現,通過發送load命令來加載agent
3.4、JVM Attach機制
jvm attach機制上JVM提供的一種JVM進程間通信的功能,能讓一個進程傳命令給另一個進程,並進行一些內部的操作,比如進行線程dump,那么就需要執行jstack進行,然后把pid等參數傳遞給需要dump的線程來執行,這就是一種java attach。
3.5、Class Transform的實現
第一次類加載的時候要求被transform的場景,在加載類文件的時候發出ClassFileLoad事件,交給instrument agent來調用java agent里注冊的ClassFileTransformer實現字節碼的修改
3.6、Class Redefind的實現
類重新定義,主要用在已經被加載的類上
四、實現字節碼增強的技術框架有哪些?
原理了解清楚了就需要實現,java agent實現字節碼增強到過程大概是:
1.修改字節碼、2.加載新到字節碼、3.替換舊的字節碼
第二步可以通過自定義ClassLoader來加載修改的字節碼,第三步可以通過JVM加載或運行字節碼時進行替換,那么第一步修改字節碼該如何進行呢,至少大部分人時不會修改的,那么就需要使用工具來修改,
目前實現修改字節碼的工具主要有ASM、Javassist和byte buddy,下一篇將着重介紹這三種字節碼生成框架及用法