天天看點

Java動态程式設計——Javassist

動态程式設計是相對于靜态程式設計而言的,平時我們讨論比較多的就是靜态程式設計語言,例如Java,與動态程式設計語言,例如JavaScript。

在靜态程式設計中,類型檢查是在編譯時完成的,而動态程式設計中類型檢查是在運作時完成的。所謂動态程式設計就是繞過編譯過程在運作時進行操作的技術,在Java中有如下幾種方式:

~~~~反射:就是通過在運作時獲得類型資訊然後做相應的操作。

~~~~動态編譯:動态編譯是從Java 6開始支援的,主要是通過一個JavaCompiler接口來完成的。通過這種方式我們可以直接編譯一個已經存在的java檔案,也可以在記憶體中動态生成Java代碼,動态編譯執行。

~~~~調用JavaScript引擎:Java 6加入了對Script(JSR223)的支援。這是一個腳本架構,提供了讓腳本語言來通路Java内部的方法。你可以在運作的時候找到腳本引擎,然後調用這個引擎去執行腳本。這個腳本API允許你為腳本語言提供Java支援。

~~~~動态生成位元組碼:這種技術通過操作Java位元組碼的方式在JVM中生成新類或者對已經加載的類動态添加元素。

動态程式設計解決什麼問題

在靜态語言中引入動态特性,主要是為了解決一些使用場景的問題。

完全使用靜态程式設計也辦的到,隻是付出的代價比較高,沒有動态程式設計來的優雅。例如依賴注入架構Spring使用了反射,而Dagger2 卻使用了代碼生成的方式(APT)。

如 

1、在那些依賴關系需要動态确認的場景: 

2、需要在運作時動态插入代碼的場景,比如動态代理的實作。 

3、通過配置檔案來實作相關功能的場景

Javassist

操作java位元組碼的工具BECL/ASM/CGLIB/Javassit

其中有兩個比較流行,一個是ASM,一個是Javassit。

ASM 直接操作位元組碼指令,執行效率高,要是使用者掌握Java類位元組碼檔案格式及指令,對使用者的要求比較高。

Javassit 提供了更進階的API,執行效率相對較差,但無需掌握位元組碼指令的知識,對使用者要求較低。

Javassit 是一個開源的分析、編輯和建立Java位元組碼的類庫。是由東京工業大學的數學和計算機科學系的 Shigeru Chiba (千葉 滋)所建立的。它已加入了開放源代碼JBoss應用伺服器項目,通過使用Javassist對位元組碼操作為JBoss實作動态AOP架構。javassist是jboss的一個子項目,其主要的優點,在于簡單,而且快速。直接使用java編碼的形式,而不需要了解虛拟機指令,就能動态改變類的結構,或者動态生成類。

Javassist中最為重要的是ClassPool,CtClass ,CtMethod 以及 CtField這幾個類。

ClassPool:一個基于HashMap實作的CtClass對象容器,其中鍵是類名稱,值是表示該類的CtClass對象。預設的ClassPool使用與底層JVM相同的類路徑,是以在某些情況下,可能需要向ClassPool添加類路徑或類位元組。

CtClass:表示一個類,這些CtClass對象可以從ClassPool獲得。

CtMethods:表示類中的方法。

CtFields :表示類中的字段。

例子:

建立Class,Field,Method,Constructor

    public static void main(String[] args) throws Exception {
        ClassPool pool = ClassPool.getDefault();
        CtClass person = pool.makeClass("com.temp.bytecodeop.Person");
        
        //建立屬性
        CtField name = CtField.make("private String name;", person);
        CtField age = CtField.make("private int age;", person);
        person.addField(name);
        person.addField(age);
        
        //建立方法
        CtMethod getName = CtMethod.make("public String getName(){return name;}", person);
        CtMethod setName = CtMethod.make("public void setName(String name){this.name=name;}", person);
        person.addMethod(getName);
        person.addMethod(setName);
        
        //建立構造器        
        CtConstructor constructor = new CtConstructor(new CtClass[]{pool.get("java.lang.String"),CtClass.intType},person);
        constructor.setBody("{this.name=name; this.age=age;}");
        person.addConstructor(constructor);
        
        person.writeFile("c:/Person");
        System.out.println("success");
    }      

參考文獻:https://blog.csdn.net/ShuSheng0007/article/details/81269295

https://www.cnblogs.com/sunfie/p/5154246.html