- 深入解析Java虛擬機(jī)HotSpot
- 楊易
- 675字
- 2021-01-07 11:18:27
2.4 類的重定義
加載、鏈接、初始化是標(biāo)準(zhǔn)的類可用機(jī)制,除此之外,Java提供了一個(gè)用于特殊場景的類重定義功能,由JDK 5引入的java.lang.instrument.Instrumentation實(shí)現(xiàn)。
Instrumentation可以在應(yīng)用程序運(yùn)行時(shí)修改或者增加類的字節(jié)碼,然后替換原來的類的字節(jié)碼,這種方式又稱為熱替換,如代碼清單2-16所示:
代碼清單2-16 Num類重定義
// Num.java public class Num { public int getNum() { return 3; } } // java -javaagent:AgentMain.jar ... import java.lang.instrument.Instrumentation; public class AgentMain { public static void premain(String args, Instrumentation inst) { inst.addTransformer((loader, className, classBeingRedefined, protectionDomain, byteCode) -> { // 修改Num.getNum()的字節(jié)碼,使它返回1 if("Num".equals(className)){ byteCode[261] = 4; } return byteCode; }); try { inst.retransformClasses(Num.class); } catch (UnmodifiableClassException e) { e.printStackTrace(); } } }
在這段代碼中,AgentMain首先添加了類字節(jié)碼轉(zhuǎn)換器,然后觸發(fā)Num類的轉(zhuǎn)換。這時(shí)會(huì)調(diào)用之前添加的類字節(jié)碼轉(zhuǎn)換器,在上面的例子中,轉(zhuǎn)換器將修改Num.getNum的代碼,使它返回整數(shù)1。然后每當(dāng)需要加載一個(gè)類時(shí),虛擬機(jī)會(huì)檢查類是否為Num類,如果是則修改它的字節(jié)碼。如果將Instrumentation與asm、cglib、Javaassist等字節(jié)碼增強(qiáng)框架結(jié)合使用,開發(fā)者可以靈活地在運(yùn)行時(shí)修改任意類的方法實(shí)現(xiàn),這樣無須修改源代碼,也無須重編譯運(yùn)行就能改變方法的行為,達(dá)到近似熱更新的效果。
注意,如果類字節(jié)碼轉(zhuǎn)換器沒有修改字節(jié)碼,正確的做法是返回null,如果修改了字節(jié)碼,應(yīng)該創(chuàng)建一個(gè)新的byte[]數(shù)組,將原來的byteCode復(fù)制到新數(shù)組中,然后修改新數(shù)組,而不是像代碼清單2-16一樣修改原有的byteCode再返回。這樣直接修改byteCode可能會(huì)造成虛擬機(jī)崩潰的情況。
Instrumentation的底層實(shí)現(xiàn)是基于JVMTI(Java虛擬機(jī)工具接口)的RedefineClasses。虛擬機(jī)創(chuàng)建VM_RedefineClasses,投遞給VMThread,然后等待VMThread執(zhí)行VM_RedefineClasses::redefine_single_class重定義一個(gè)類。類的重定義是一個(gè)煩瑣的過程,它會(huì)移除原來類(the_class)中的所有斷點(diǎn),所有依賴原來類的編譯后的代碼都需要進(jìn)行退優(yōu)化,原來類的方法、常量池、內(nèi)部類、虛表、接口表、調(diào)試信息、版本號(hào)、方法指紋等數(shù)據(jù)也會(huì)一并被替換為新的類定義(scratch_class)中的數(shù)據(jù)。
- Functional Python Programming
- 程序員面試筆試寶典
- 編程珠璣(續(xù))
- Learning AWS Lumberyard Game Development
- Mastering LibGDX Game Development
- Bootstrap 4:Responsive Web Design
- Visual Basic程序設(shè)計(jì)實(shí)驗(yàn)指導(dǎo)(第二版)
- Learning Node.js for .NET Developers
- 自學(xué)Python:編程基礎(chǔ)、科學(xué)計(jì)算及數(shù)據(jù)分析(第2版)
- Learning JavaScript Data Structures and Algorithms(Second Edition)
- Java Web開發(fā)實(shí)例大全(基礎(chǔ)卷) (軟件工程師開發(fā)大系)
- Java程序設(shè)計(jì)基礎(chǔ)(第6版)
- 零基礎(chǔ)學(xué)C++(升級(jí)版)
- 現(xiàn)代CPU性能分析與優(yōu)化
- SQL Server實(shí)例教程(2008版)