首頁/ 汽車/ 正文

1000個字帶你一次性搞懂JavaAgent技術,反正我是徹底服了

JavaAgent技術

JavaAgent是一種特殊的Java程式,是Instrumentation的客戶端。它與普通Java程式透過main方法啟動不同,JavaAgent並不是一個可以單獨啟動的程式,它必須依附在一個Java應用程式(JVM)上,與主程式執行在同一個程序中,透過Instrumentation API與虛擬機器互動。

JVM啟動時靜態載入

對於JVM啟動時載入的Agent模組程式碼,Instrumentation會透過premain方法傳入代理程式,premain方法會在呼叫程式main方法之前被呼叫,同時Instrumentation包含agentmain方法實現位元組碼改寫,二者的區別如下:

● premain 方 法 用 於 在 啟 動 時 , 在 類 加 載 前 定 義 類 的TransFormer(轉化器),在類載入的時候更新對應的類的位元組碼。

● agentmain方法用於在執行時進行類的位元組碼的修改,步驟分為註冊類的TransFormer呼叫和retransformClasses函式進行類的重載入。

premain方法與agentmain方法相比有很大的侷限性。premain方法僅限於應用程式的啟動時,即main函式執行前。此時還有很多類沒有被載入,而這些類使用premain方法是無法實現位元組碼改寫的。

目前,主流的基於探針的監控系統都是基於這種方式實現的對應用的無侵入監控。我們知道程式的入口是main方法,而premain方法代表了在程式正式啟動之前執行的動作,它同時具備類似AOP的能力。

Transformer提供位元組碼檔案流轉化的能力,如下圖所示是Class檔案轉換圖。

1000個字帶你一次性搞懂JavaAgent技術,反正我是徹底服了

位元組碼改寫

如上圖所示,任何Class檔案在載入時,都要經過premain這一程式碼轉換環節。透過一系列的TransFormer轉換,Class位元組碼檔案流最終轉變為我們期望的程式碼實現,然後被載入到JVM中。修改Class位元組碼檔案流的動作是在Transformer中進行的。我們可以使用Javaassist技術修改位元組碼檔案流(下一節介紹)。下面就是我們實現的一個類 , 實 現 了 帶 Instrumentation 參 數 的 premain 方 法 。 調 用addTransformer方法對啟動時所有的類進行攔截,示例程式碼如下:

1000個字帶你一次性搞懂JavaAgent技術,反正我是徹底服了

1000個字帶你一次性搞懂JavaAgent技術,反正我是徹底服了

JVM啟動後動態Instrument機制

關於JVM啟動後動態載入Agent的方法,Instrumentation會透過agentmain方法傳入程式。agentmain方法在main函式開始執行後才被呼叫,其最大優勢是可以在程式執行期間進行位元組碼的替換。

Attach API

[1]

實現動態注入的原理如下。

你的應用程式透過虛擬機器提供的attach(pid)方法,可以將代理程式連線(attach)到一個執行中的Java程序上,之後便可以透過loadAgent(AgentJarPath)將Agent的jar包注入對應的程序,然後對應的程序會呼叫agentmain方法,如下圖所示。

1000個字帶你一次性搞懂JavaAgent技術,反正我是徹底服了

工程結構和上面premain的一樣,編寫AgentMainTest程式碼示例如下:

1000個字帶你一次性搞懂JavaAgent技術,反正我是徹底服了

1000個字帶你一次性搞懂JavaAgent技術,反正我是徹底服了

JavaAgent執行前啟動載入代理程式的方法如下。

JavaAgent有兩個啟動時機,一個是在程式啟動時透過-javaAgent引數啟動代理程式;另一個是在程式執行期間透過Java Tool API中的Attach API動態啟動代理程式。我們透過-javaAgent來指定我們編寫的Agent的jar路徑(。/{Location}/Agent。jar)。這樣在啟動時,Agent就可以做定製化的位元組碼改動了。對於Spring Boot類內建容器的服務,可以使用下面方式:

1000個字帶你一次性搞懂JavaAgent技術,反正我是徹底服了

在Tomcat啟動時,它會讀取CATALINA_OPTS環境變數,並將它加入啟動命令中。在環境變數中新增如下資訊:

1000個字帶你一次性搞懂JavaAgent技術,反正我是徹底服了

Java程式執行後加載代理的方法如下。

程式啟動之後,我們透過某種特定的手段載入Java Agent。這個特定的手段就是虛擬機器的Attach API。這個API其實是JVM程序之間的溝通橋樑,它的底層透過Socket進行通訊。JVM A可以傳送一些指令給JVM B,JVM B收到指令之後,可以執行對應的邏輯,比如在命令列中經常使用的jstack、jcmd、jps等命令。因為是程序間通訊,所以使用Attach API的也是一個獨立的Java程序。下面是一個簡單的實現,程式碼示例如下:

1000個字帶你一次性搞懂JavaAgent技術,反正我是徹底服了

本文給大家講解的內容是服務監控治理, JavaAgent技術

下篇文章給大家講解的內容是服務監控治理,Javaassist技術

覺得文章不錯的朋友可以轉發此文關注小編;

感謝大家的支援!

相關文章

頂部