官术网_书友最值得收藏!

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ù)。

主站蜘蛛池模板: 临沭县| 湘西| 内乡县| 绥化市| 遂川县| 宜黄县| 兴安盟| 屏东县| 边坝县| 博野县| 平邑县| 左贡县| 白河县| 邹平县| 阿巴嘎旗| 洛浦县| 措勤县| 芮城县| 孝义市| 金昌市| 南京市| 香港 | 花莲县| 万安县| 清流县| 梧州市| 仙桃市| 科技| 高陵县| 安泽县| 牙克石市| 定日县| 北川| 稻城县| 民和| 太湖县| 石家庄市| 剑河县| 富锦市| 嘉鱼县| 清新县|