Java Agent入門實戰(二)-Instrumentation原始碼概述

蔣老溼發表於2020-01-06

Instrumentation介面設計初衷是為了收集Java程式執行時的資料,用於監控執行程式狀態,記錄日誌,分析程式碼用的。接下來從原始碼的流程來介紹一下

Java Agent入門實戰(二)-Instrumentation原始碼概述

實現類InstrumentationImpl的void addTransformer(ClassFileTransformer transformer, boolean canRetransform);

Java Agent入門實戰(二)-Instrumentation原始碼概述

從這段程式碼知道,轉換器ClassFileTransformer的實現是儲存在TransformerManager的TransformerInfo陣列中的,陣列初始長度為0,每新增一個,陣列長度為原來的長度+1,將原陣列內容拷貝到新陣列中。

Java Agent入門實戰(二)-Instrumentation原始碼概述

VirtualMachine.attach

Java Agent入門實戰(二)-Instrumentation原始碼概述

進入AttachProvider.providers(),這裡面會初始化AttachProvider,並返回一個AttachProvider List

Java Agent入門實戰(二)-Instrumentation原始碼概述

進入ServiceLoader.load(AttachProvider.class, AttachProvider.class.getClassLoader());

Java Agent入門實戰(二)-Instrumentation原始碼概述
Java Agent入門實戰(二)-Instrumentation原始碼概述

繼續跟進方法 new LazyIterator(service, loader)

Java Agent入門實戰(二)-Instrumentation原始碼概述

看一下com.sun.tools jar包下的META-INF/services/目錄,開啟 com.sun.tools.attach.spi.AttachProvider, 可以看到有不同平臺作業系統的實現,我的是windows,會呼叫windos的實現sun.tools.attach.WindowsAttachProvider。其他的都被註釋掉了。程式碼看到這,就知道ServiceLoader.load方法最終載入的是sun.tools.attach.WindowsAttachProvider

Java Agent入門實戰(二)-Instrumentation原始碼概述

Java Agent入門實戰(二)-Instrumentation原始碼概述

上文hasNextService()方法下面的nextService()

Java Agent入門實戰(二)-Instrumentation原始碼概述

回到最初的VirtualMachine.attach(String var0)方法,進入return var4.attachVirtualMachine(var0);attachVirtualMachine()

Java Agent入門實戰(二)-Instrumentation原始碼概述
Java Agent入門實戰(二)-Instrumentation原始碼概述
Java Agent入門實戰(二)-Instrumentation原始碼概述

通過 ClassLoader 類中的findNative方法,可以找到JVM原始碼中的一些native方法呼叫名,這樣可以關聯著JVM原始碼看底層的C++原始碼到底做了啥

Java Agent入門實戰(二)-Instrumentation原始碼概述

發現在attach.dll中找方法名為Java_sun_tools_attach_WindowsVirtualMachine_openProcessnative method

Java Agent入門實戰(二)-Instrumentation原始碼概述

嘗試性的在jdk原始碼裡去找這2個方法Java_sun_tools_attach_WindowsVirtualMachine_openProcessJava_sun_tools_attach_WindowsVirtualMachine_enqueue

Java Agent入門實戰(二)-Instrumentation原始碼概述
Java Agent入門實戰(二)-Instrumentation原始碼概述

virtualMachine.loadAgent()、 virtualMachine.detach()原始碼流程和上述類似,也和平臺相關,這裡就不在贅述了。

RedefineClasse配置注意事項

可以在執行期對已載入類的位元組碼做變更,但是這種情況下會有很多的限制 對比新老類,並要求如下:

  • 父類是同一個
  • 實現的介面數也要相同,並且是相同的介面
  • 類訪問符必須一致
  • 欄位數和欄位名要一致
  • 新增的方法必須是 private static/final 的
  • 可以刪除修改方法

參考

JVM 原始碼分析之javaagent 原理完全解讀

點關注,不迷路

文章每週持續更新,可以微信搜尋「 十分鐘學程式設計 」第一時間閱讀和催更,如果這個文章寫得還不錯,覺得有點東西的話 ~求點贊? 求關注❤️ 求分享❤️
各位的支援和認可,就是我創作的最大動力,我們下篇文章見!

相關文章