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







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章