Instrumentation介面設計初衷是為了收集Java程式執行時的資料,用於監控執行程式狀態,記錄日誌,分析程式碼用的。接下來從原始碼的流程來介紹一下
實現類InstrumentationImpl的void addTransformer(ClassFileTransformer transformer, boolean canRetransform);
從這段程式碼知道,轉換器ClassFileTransformer的實現是儲存在TransformerManager的TransformerInfo陣列中的,陣列初始長度為0,每新增一個,陣列長度為原來的長度+1,將原陣列內容拷貝到新陣列中。
VirtualMachine.attach
進入AttachProvider.providers()
,這裡面會初始化AttachProvider
,並返回一個AttachProvider List
。
進入ServiceLoader.load(AttachProvider.class, AttachProvider.class.getClassLoader());
繼續跟進方法 new LazyIterator(service, loader)
看一下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
。
上文hasNextService()
方法下面的nextService()
回到最初的VirtualMachine.attach(String var0)
方法,進入return var4.attachVirtualMachine(var0);
的attachVirtualMachine()
內
通過 ClassLoader 類中的findNative
方法,可以找到JVM原始碼中的一些native方法呼叫名,這樣可以關聯著JVM原始碼看底層的C++原始碼到底做了啥
發現在attach.dll中找方法名為Java_sun_tools_attach_WindowsVirtualMachine_openProcess
native method
嘗試性的在jdk原始碼裡去找這2個方法Java_sun_tools_attach_WindowsVirtualMachine_openProcess
和Java_sun_tools_attach_WindowsVirtualMachine_enqueue
virtualMachine.loadAgent()、 virtualMachine.detach()
原始碼流程和上述類似,也和平臺相關,這裡就不在贅述了。
RedefineClasse配置注意事項
可以在執行期對已載入類的位元組碼做變更,但是這種情況下會有很多的限制 對比新老類,並要求如下:
- 父類是同一個
- 實現的介面數也要相同,並且是相同的介面
- 類訪問符必須一致
- 欄位數和欄位名要一致
- 新增的方法必須是 private static/final 的
- 可以刪除修改方法
參考
點關注,不迷路
文章每週持續更新,可以微信搜尋「 十分鐘學程式設計 」第一時間閱讀和催更,如果這個文章寫得還不錯,覺得有點東西的話 ~求點贊? 求關注❤️ 求分享❤️
各位的支援和認可,就是我創作的最大動力,我們下篇文章見!