技術問答集錦(13)Java Instrument原理

猿碼道發表於2018-04-17

1 Java Instrument能做什麼?最大的作用?

  1. 使開發者可以構建一個獨立於應用程式的代理程式Agent,用來監控和協助執行在JVM上的程式,更重要的是能夠替換和修改某些類的定義;

  2. 最大的作用:可以實現一種虛擬機器級別支援的AOP實現方式;

2 在JDK 1.5 、1.6中,Java Instrument做了哪些變動支援?

  1. JDK 1.5:支援靜態Instrument,就是在JVM啟動前靜態設定Instrument;

  2. JDK 1.6:支援動態Instrument,就是在JVM啟動後動態設定Instrument;支援原生程式碼Instrument;支援動態改變classpath;

3 Java Instrument的實現是基於JVM哪種機制?JVMTI是什麼,可以做什麼?

  1. 基於JVMTI代理程式;
  2. JVMTI:一套代理程式機制,為JVM相關工具提供的本地程式設計介面集合;
  3. JVMTI可以支援第三方工具程式以代理的方式連線和訪問JVM,並利用JVMTI提供的豐富的程式設計介面,完成很多跟JVM相關的功能;

4 Instrument premain、agentmain方法執行時機?

  1. premain執行時機:在JVM啟動時,初始化函式eventHandlerVMinit會呼叫sun.instrument.instrumentationImpl類的loadClassAndCallPremain方法去執行Premain-Class指定類的premain方法;
  2. agentmain執行時機:在JVM啟動後,通過VirtualMachine附著一個Instrument,如:vm.loadAgent(jar),會呼叫sun.instrument.instrumentationImpl類的loadClassAndCallAgentmain方法去執行Agentmain-Class指定類的agentmain方法;

5 Instrument premain、agentmain方法中兩個引數agentArgs、inst代表什麼?分別會有什麼作用?

  1. agentArgs:代理程式命令列中輸入引數,隨同“-javaagent”一起傳入,與main函式不同的是,這個引數是一個字串而不是一個字串陣列;
  2. inst:java.lang.instrument.Instrumentation例項,由JVM自動傳入,集中了幾乎所有功能方法,如:類操作、classpath操作等;

6 java.lang.instrument.ClassFileTransformer是什麼,有什麼作用?

  1. ClassFileTransformer當中的transform方法可以對類定義進行操作修改;
  2. 在類位元組碼載入JVM前,JVM會呼叫ClassFileTransformer.transform方法,從而實現對類定義進行操作修改,實現AOP功能;相對於JDK 動態代理、CGLIB等AOP實現技術,不會生成新類,也不需要原類有介面;

7 對於agentmain方法執行,如何進行動態attach agent?

通過VirtualMachine附著一個Instrument,如:vm.loadAgent(jar);

8 META-INF/MAINFEST.MF引數清單?

  1. Premain-Class:指定包含premain方法的類名;
  2. Agent-Class:指定包含agentmain方法的類名;
  3. Boot-Class-Path:指定引導類載入器搜尋的路徑列表。查詢類的特點於平臺的機制失敗後,引導類載入器會搜尋這些路徑;
  4. Can-Redefine-Class:是否能重新定義此代理所需的類,預設為false;
  5. Can-Retransform-Class:是否能重新轉換此代理所需的類,預設為false;
  6. Can-Set-Native-Method-Prefix:是否能設定此代理所需的本機方法字首,預設值為false;

9 兩個核心API ClassFileTransformer、Instrumention?

  1. ClassFileTransformer:定義了類載入前的預處理類;
  2. Instrumentation:增強器

(1)add/removeTransformer:新增/刪除ClasFileTransformer;

(2)retransformerClasses:指定哪些類,在已載入的情況下,重新進行轉換處理,即觸發重新載入類定義;對於重新載入的類不能修改舊有的類宣告,比如:不能增加屬性、不能修改方法宣告等;

(3)redefineClasses:指定哪些類,觸發重新載入類定義,與上面不同的是不會重新進行轉換處理,而是把處理結果bytecode直接給JVM;

(4)getAllLoadedClasses:獲取當前已載入的Class集合;

(5)getInitiatedClasses:獲取由某個特定ClassLoader載入的類定義;

(6)getObjectSize:獲得一個物件佔用的空間大小;

(7)appendToBootstrapClassLoaderSearch/appentToSystemClassLoaderSearch:增加BootstrapClassLoader/SystemClassLoader搜尋路徑;

(8)isNativeMethodPrefixSupported/SetNativeMethodPrefix:判斷JVM是否支援攔截Native Method;

10 Java Instrument工作原理?

  1. 在JVM啟動時,通過JVM引數-javaagent,傳入agent jar,Instrument Agent被載入;
  2. 在Instrument Agent 初始化時,註冊了JVMTI初始化函式eventHandlerVMinit;
  3. 在JVM啟動時,會呼叫初始化函式eventHandlerVMinit,啟動了Instrument Agent,用sun.instrument.instrumentationImpl類裡的方法loadClassAndCallPremain方法去初始化Premain-Class指定類的premain方法;
  4. 初始化函式eventHandlerVMinit,註冊了class解析的ClassFileLoadHook函式;
  5. 在解析Class之前,JVM呼叫JVMTI的ClassFileLoadHook函式,鉤子函式呼叫sun.instrument.instrumentationImpl類裡的transform方法,通過TransformerManager的transformer方法最終呼叫我們自定義的Transformer類的transform方法;
  6. 因為位元組碼在解析Class之前改的,直接使用修改後的位元組碼的資料流替代,最後進入Class解析,對整個Class解析無影響;
  7. 重新載入Class依然重新走5-6步驟;

相關文章