效能最佳化專題10-位元組碼技術

位元組碼技術

效能最佳化專題10-位元組碼技術

位元組碼技術應用場景

AOP技術、Lombok去除重複程式碼外掛、動態修改class檔案等

位元組技術優勢

Java位元組碼增強指的是在Java位元組碼生成之後,對其進行修改,增強其功能,這種方式相當於對應用程式的二進位制檔案進行修改。Java位元組碼增強主要是為了減少冗餘程式碼,提高效能等。

實現位元組碼增強的主要步驟為:

1、修改位元組碼

在記憶體中獲取到原來的位元組碼,然後透過一些工具(如 ASM,Javaasist)來修改它的byte[]陣列,得到一個新的byte陣列。

2、使修改後的位元組碼生效

有兩種方法:

1) 自定義ClassLoader來載入修改後的位元組碼;

2)替換掉原來的位元組碼:在JVM載入使用者的Class時,攔截,返回修改後的位元組碼;或者在執行時,使用Instrumentation.redefineClasses方法來替換掉原來的位元組碼

常見的位元組碼操作類庫

BCEL

Byte Code Engineering Library(BCEL),這是Apache Software Foundation的Jakarta專案的一部分。BCEL是Java classworking 廣泛使用的一種框架,它可以讓您深入jvm組合語言進行類庫操作的細節。BCEL與javassist有不同的處理位元組碼方法,BCEL在實際的jvm指令層次上進行操作(BCEL擁有豐富的jvm指令集支援) 而javassist所強調的是原始碼級別的工作。

ASM

是一個輕量級Java位元組碼操作框架,直接涉及到JVM底層的操作和指令

高效能,高質量

CGLB

生成類庫,基於ASM實現

javassist

是一個開源的分析,編輯和建立Java位元組碼的類庫。效能較ASM差,跟cglib差不多,但是使用簡單。很多開源框架都在使用它。

Javassist優勢

– 比反射開銷小,效能高。

–javassist效能高於反射,低於ASM

執行時操作位元組碼可以讓我們實現如下功能:

– 動態生成 新的類

– 動態改變某個類的結構 ( 新增 / 刪除 / 修改 新的屬性 / 方法 )

javassist 的最外層的 API 和 JAVA 的反射包中的 API 頗為 類似 。

它 主要 由 CtClass , CtMethod, ,以及 CtField 幾個類組成。用以執行和 JDK 反射 API 中 java。lang。Class, java。lang。reflect。Method, java。lang。reflect。Method 。Field 相同的 操作 。

方法操作

– 修改已有方法的方法體(插入程式碼到已有方法體)

– 新增方法 刪除方法

javassist的侷限性

JDK5。0 新語法不支援 ( 包括泛型、列舉 ) ,不支援註解修改,但可以透過底層的 javassist 類來解決,具體參考: javassist。bytecode。annotation不支援陣列的初始化,如 String[]{“1”,“2”} ,除非只有陣列的容量為 1不支援內部類和匿名類不支援 continue 和 break表示式。對於繼承關係,有些不支援。例如class A {} class B extends A {} class C extends B {}

使用Javassist建立類

public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException { Class<?> clazz = Class。forName(“com。itmayiedu。Test0005”); Object newInstance = clazz。newInstance(); Method method = clazz。getDeclaredMethod(“sum”, int。class, int。class); Object invoke = method。invoke(newInstance, 1, 1); } public void sum(int a, int b) { System。out。println(“sum:” + a + b); }

public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException { ClassPool pool = ClassPool。getDefault(); // 建立class檔案 CtClass userClass = pool。makeClass(“com。itmayiedu。entity。User”); // 建立id屬性 CtField idField = CtField。make(“private Integer id;”, userClass); // 建立name屬性 CtField nameField = CtField。make(“private Integer name;”, userClass); // 新增屬性 userClass。addField(idField); // 新增屬性 userClass。addField(nameField); // 建立方法 CtMethod getIdMethod = CtMethod。make(“public Integer getId() {return id;}”, userClass); // 建立方法 CtMethod setIdMethod = CtMethod。make(“public void setId(Integer id) { this。id = id; }”, userClass); // 新增方法 userClass。addMethod(getIdMethod); // 新增方法 userClass。addMethod(setIdMethod); // 新增構造器 CtConstructor ctConstructor = new CtConstructor(new CtClass[] { CtClass。intType, pool。get(“java。lang。String”) }, userClass); // 建立Body ctConstructor。setBody(“ {this。id = id;this。name = name;}”); userClass。addConstructor(ctConstructor); userClass。writeFile(“F:/test”);// 將構造好的類寫入到F:\test 目錄下 }

使用Javassist修改類檔案資訊

public static void main(String[] args) throws NotFoundException, CannotCompileException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException, IOException { ClassPool pool = ClassPool。getDefault(); // 需要載入類資訊 CtClass userClass = pool。get(“com。itmayiedu。User”); // 需要新增的方法 CtMethod m = new CtMethod(CtClass。intType, “add”, new CtClass[] { CtClass。intType, CtClass。intType }, userClass); // 方法許可權 m。setModifiers(Modifier。PUBLIC); // 方法體內容 m。setBody(“{System。out。println(\”Test003\“); return $1+$2;}”); userClass。addMethod(m); userClass。writeFile(“F:/test”);// 將構造好的類寫入到F:\test 目錄下 // 使用反射技術執行方法 Class clazz = userClass。toClass(); Object obj = clazz。newInstance(); // 透過呼叫User 無參建構函式 Method method = clazz。getDeclaredMethod(“add”, int。class, int。class); Object result = method。invoke(obj, 200, 300); System。out。println(result); }