字節碼應用場景
AOP 技術、Lombok 去除重複代碼插件、動態修改 class 文件等
字節碼技術優點
Java 字節碼加強指的是在 Java 字節碼生成以後,對其進行修改,加強其功能,這種方式至關於對應用程序的二進制文件進行修改,Java 字節碼加強主要是爲了減小冗餘代碼,提升性能等 實現字節碼加強的主要步驟爲:
修改字節碼,在內存中獲取到原來的字節碼,而後經過一些工具(如 ASM,Javaasist)來修改它的byte[]數組,獲得一個新的byte數組
使修改後的字節碼生效java
自定義 ClassLoader 來加載修改後的字節碼
替換掉原來的字節碼,在 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 中最爲重要的是 ClassPool、CtClass 、CtMethod、CtField
ClassPool:一個基於HashMap實現的 CtClass 對象容器,其中鍵是類名稱,值是表示該類的 CtClass 對象,默認的ClassPool 使用與底層 JVM 相同的類路徑,所以在某些狀況下,可能須要向 ClassPool 添加類路徑或類字節
CtClass:表示一個類,這些 CtClass 對象能夠從 ClassPool 得到
CtMethods:表示類中的方法
CtFields :表示類中的字段
優點:
比反射開銷小、性能高
操做字節碼能夠動態生成新的類,動態修改類(添加、刪除、修改屬性或方法)
javassist 外層 API 和反射相似
主要有 CtClass、CtMethod、CtField 組成,執行反射中的 java.lang.Class、java.lang.reflect.Method、 java.lang.reflect.Method .Field 中的操做
劣勢:
不支持 JDK5 的新語法,包括泛型、枚舉,不支持註解修改
不支持數組初始化
不支持內部類和匿名類
不支持 continue 和 break
動態建立類
public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException {
ClassPool pool = ClassPool.getDefault();
// 建立User
CtClass userClass = pool.makeClass("com.kernel.entity.User");
// 建立屬性
CtField nameField = CtField.make("private String name;", userClass);
CtField ageField = CtField.make("private Integer age;", userClass);
// 添加屬性
userClass.addField(nameField);
userClass.addField(ageField);
// 建立方法
CtMethod getName = CtMethod.make("public String getName() {return name;}", userClass);
CtMethod setName = CtMethod.make("public void setName(String name) {this.name = name;}", userClass);
// 添加方法
userClass.addMethod(getName);
userClass.addMethod(setName);
// 建立構造器
CtConstructor constructor = new CtConstructor(new CtClass[]{pool.get("java.lang.String"), pool.get("java.lang.Integer")}, userClass);
// 設置內容
constructor.setBody("{this.name = name;this.age = age;}");
// 添加構造器
userClass.addConstructor(constructor);
userClass.writeFile("D:\Codes\Java\Performance\jvm-day03\src\main\java\com\kernel\test");
}
動態添加並執行方法
public static void main(String[] args) {
try {
ClassPool pool = ClassPool.getDefault();
// 讀取com.kernel.User
CtClass userClass = pool.get("com.kernel.User");
// 建立方法,設置方法返回值
CtMethod method = new CtMethod(CtClass.voidType, "sum", new CtClass[] { CtClass.intType, CtClass.intType },
userClass);
// 設置方法內容
method.setBody("{System.out.println(\"sun:\" + ($1 + $2));}");
// 添加方法
userClass.addMethod(method);
userClass.writeFile("D:\Codes\Java\Performance\jvm-day03\src\main\java\com\kernel\test");
// 動態執行方法
Class clazz = userClass.toClass();
Object newInstance = clazz.newInstance();
// 得到方法
Method sumMethod = clazz.getDeclaredMethod("sum", int.class, int.class);
sumMethod.invoke(newInstance, 2, 5);
} catch (Exception e) {
e.printStackTrace();
}
}數組