Java字節(jié)碼增強技術知識點詳解
簡單介紹下幾種java字節(jié)碼增強技術。
ASM
ASM是一個Java字節(jié)碼操控框架,它能被用來動態(tài)生成類或者增強既有類的功能。ASM可以直接產生class文件,也可以在類被加載入Java虛擬機之前動態(tài)改變類行為。ASM從類文件中讀入信息后,能夠改變類行為,分析類信息,甚至能夠根據用戶要求生成新類。
主頁:https://asm.ow2.io/index.html
ASM框架中的核心類有以下幾個:
① ClassReader:該類用來解析編譯過的class字節(jié)碼文件。
② ClassWriter:該類用來重新構建編譯后的類,比如說修改類名、屬性以及方法,甚至可以生成新的類的字節(jié)碼文件。
③ ClassAdapter:該類也實現(xiàn)了ClassVisitor接口,它將對它的方法調用委托給另一個ClassVisitor對象。
參考代碼:
import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Opcodes; public class GeneratorClass { public static void main(String[] args) throws IOException { //生成一個類只需要ClassWriter組件即可 ClassWriter cw = new ClassWriter(0); //通過visit方法確定類的頭部信息 cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC+Opcodes.ACC_ABSTRACT+Opcodes.ACC_INTERFACE, "com/asm3/Comparable", null, "java/lang/Object", new String[]{"com/asm3/Mesurable"}); //定義類的屬性 cw.visitField(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL+Opcodes.ACC_STATIC, "LESS", "I", null, new Integer(-1)).visitEnd(); cw.visitField(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL+Opcodes.ACC_STATIC, "EQUAL", "I", null, new Integer(0)).visitEnd(); cw.visitField(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL+Opcodes.ACC_STATIC, "GREATER", "I", null, new Integer(1)).visitEnd(); //定義類的方法 cw.visitMethod(Opcodes.ACC_PUBLIC+Opcodes.ACC_ABSTRACT, "compareTo", "(Ljava/lang/Object;)I", null, null).visitEnd(); cw.visitEnd(); //使cw類已經完成 //將cw轉換成字節(jié)數組寫到文件里面去 byte[] data = cw.toByteArray(); File file = new File("D://Comparable.class"); FileOutputStream fout = new FileOutputStream(file); fout.write(data); fout.close(); } }
Javassist
Javassist是一個開源的分析、編輯和創(chuàng)建Java字節(jié)碼的類庫。
它已加入了開放源代碼JBoss應用服務器項目,通過使用Javassist對字節(jié)碼操作為JBoss實現(xiàn)動態(tài)"AOP"框架。
利用Javassist實現(xiàn)字節(jié)碼增強時,可以無須關注字節(jié)碼刻板的結構,其優(yōu)點就在于編程簡單。直接使用java編碼的形式,而不需要了解虛擬機指令,就能動態(tài)改變類的結構或者動態(tài)生成類。其中最重要的是ClassPool、CtClass、CtMethod、CtField這四個類:
CtClass(compile-time class):編譯時類信息,它是一個class文件在代碼中的抽象表現(xiàn)形式,可以通過一個類的全限定名來獲取一個CtClass對象,用來表示這個類文件。
ClassPool:從開發(fā)視角來看,ClassPool是一張保存CtClass信息的HashTable,key為類名,value為類名對應的CtClass對象。當我們需要對某個類進行修改時,就是通過pool.getCtClass(“className”)方法從pool中獲取到相應的CtClass。
CtMethod、CtField:這兩個比較好理解,對應的是類中的方法和屬性。
參考代碼:
import javassist.*; public class CreatePerson { public static void createPseson() throws Exception { ClassPool pool = ClassPool.getDefault(); // 1. 創(chuàng)建一個空類 CtClass cc = pool.makeClass("com.test.javassist.Person"); // 2. 新增一個字段 private String name; // 字段名為name CtField param = new CtField(pool.get("java.lang.String"), "name", cc); // 訪問級別是 private param.setModifiers(Modifier.PRIVATE); // 初始值是 "xiaoming" cc.addField(param, CtField.Initializer.constant("xiaoming")); // 3. 生成 getter、setter 方法 cc.addMethod(CtNewMethod.setter("setName", param)); cc.addMethod(CtNewMethod.getter("getName", param)); // 4. 添加無參的構造函數 CtConstructor cons = new CtConstructor(new CtClass[]{}, cc); cons.setBody("{name = \"xiaohong\";}"); cc.addConstructor(cons); // 5. 添加有參的構造函數 cons = new CtConstructor(new CtClass[]{pool.get("java.lang.String")}, cc); // $0=this / $1,$2,$3... 代表方法參數 cons.setBody("{$0.name = $1;}"); cc.addConstructor(cons); // 6. 創(chuàng)建一個名為printName方法,無參數,無返回值,輸出name值 CtMethod ctMethod = new CtMethod(CtClass.voidType, "printName", new CtClass[]{}, cc); ctMethod.setModifiers(Modifier.PUBLIC); ctMethod.setBody("{System.out.println(name);}"); cc.addMethod(ctMethod); //這里會將這個創(chuàng)建的類對象編譯為.class文件 cc.writeFile("/Users/yangyue/workspace/springboot-learn/java-agent/src/main/java/"); } public static void main(String[] args) { try { createPseson(); } catch (Exception e) { e.printStackTrace(); } } }
Byte Buddy
Byte Buddy是一個代碼生成和操作庫,用于在Java應用程序運行時創(chuàng)建和修改Java類,而無需編譯器的幫助。
除了Java類庫附帶的代碼生成實用程序外,Byte Buddy還允許創(chuàng)建任意類,并且不限于實現(xiàn)用于創(chuàng)建運行時代理的接口。
此外,Byte Buddy提供了一種方便的API,可以使用Java代理或在構建過程中手動更改類。
參考代碼:
Class<?> dynamicType = new ByteBuddy() .subclass(Object.class) .method(ElementMatchers.named("toString")) .intercept(FixedValue.value("Hello World!")) .make() .load(getClass().getClassLoader()) .getLoaded(); assertThat(dynamicType.newInstance().toString(), is("Hello World!"));
JVM-SANDBOX
JVM沙箱容器,一種JVM的非侵入式運行期AOP解決方案:
動態(tài)增強類你所指定的類,獲取你想要的參數和行信息甚至改變方法執(zhí)行。
動態(tài)可插拔容器框架。
主頁:https://github.com/alibaba/jvm-sandbox
知識點擴充:
動態(tài)生成字節(jié)碼
我們知道,我們編寫的 Java 代碼都是要被編譯成字節(jié)碼后才能放到 JVM 里執(zhí)行的,而字節(jié)碼一旦被加載到虛擬機中,就可以被解釋執(zhí)行。
字節(jié)碼文件(.class)就是普通的二進制文件,它是通過 Java 編譯器生成的。而只要是文件就可以被改變,如果我們用特定的規(guī)則解析了原有的字節(jié)碼文件,對它進行修改或者干脆重新定義,這不就可以改變代碼行為了么。
Java 生態(tài)里有很多可以動態(tài)生成字節(jié)碼的技術,像 BCEL、Javassist、ASM、CGLib 等,它們各有自己的優(yōu)勢。有的使用復雜卻功能強大、有的簡單確也性能些差。
ASM 框架
ASM 是它們中最強大的一個,使用它可以動態(tài)修改類、方法,甚至可以重新定義類,連 CGLib 底層都是用 ASM 實現(xiàn)的。
當然,它的使用門檻也很高,使用它需要對 Java 的字節(jié)碼文件有所了解,熟悉 JVM 的編譯指令。雖然我對 JVM 的字節(jié)碼語法不熟,但有大神開發(fā)了可以在 IDEA 里查看字節(jié)碼的插件:ASM Bytecode Outline,在要查看的類文件里右鍵選擇Show bytecode Outline即可以右側的工具欄查看我們要生成的字節(jié)碼。對照著示例,我們就可以很輕松地寫出操作字節(jié)碼的 Java 代碼了。
到此這篇關于Java字節(jié)碼增強技術知識點詳解的文章就介紹到這了,更多相關Java字節(jié)碼增強技術內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- 學會Java字節(jié)碼指令,成為技術大佬
- Java之字節(jié)碼以及優(yōu)勢案例講解
- 詳解Java動態(tài)字節(jié)碼技術
- 詳解Java字節(jié)碼編程之非常好用的javassist
- 淺談javap命令拆解字節(jié)碼文件
- Java字節(jié)碼中jvm實例用法
- Javassist如何操作Java 字節(jié)碼
- Java中invokedynamic字節(jié)碼指令問題
- java獲取版本號及字節(jié)碼編譯版本方法示例
- java 獲取字節(jié)碼文件的幾種方法總結
- java 中如何獲取字節(jié)碼文件的相關內容
- java字節(jié)碼框架ASM操作字節(jié)碼的方法淺析
- java字節(jié)碼框架ASM的深入學習
- Java 將字符串動態(tài)生成字節(jié)碼的實現(xiàn)方法
- 通過java字節(jié)碼分析學習對象初始化順序
- Java字節(jié)碼的增強技術
相關文章
mybatis-plus mapper中foreach循環(huán)操作代碼詳解(新增或修改)
這篇文章主要介紹了mybatis-plus mapper中foreach循環(huán)操作代碼詳解(新增或修改),本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-11-11SpringCloud學習筆記之OpenFeign進行服務調用
OpenFeign對feign進行進一步的封裝,添加了springmvc的一些功能,更加強大,下面這篇文章主要給大家介紹了關于SpringCloud學習筆記之OpenFeign進行服務調用的相關資料,需要的朋友可以參考下2022-01-01Mybatis-Plus實現(xiàn)多主鍵批量保存及更新詳情
這篇文章主要介紹了Mybatis-Plus實現(xiàn)多主鍵批量保存及更新詳情,文章通過圍繞主題展開詳細的內容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-09-09SpringBoot整合mybatis-generator-maven-plugin的方法
這篇文章主要介紹了SpringBoot整合mybatis-generator-maven-plugin,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-11-11springMvc注解之@ResponseBody和@RequestBody詳解
本篇文章主要介紹了springMvc注解之@ResponseBody和@RequestBody詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-05-05