本篇是本系列的第二篇,主要介紹什麼是ASM,以及如何使用ASM。 若是沒有閱讀以前的教你用Java字節碼作點有趣的事,還請閱讀一下,由於須要上一章的部分需求。java
在上節咱們知道,經過javac編譯生成以後生成的是字節碼,可是咱們可能會有一些需求,好比須要AOP切面,事務的統一管理,有些重複的代碼須要咱們來回的敲,又或者咱們須要生成本身的字節碼來使用(fastjson就是這麼作的)。可是字節碼若是咱們直接操做,成本太大,而且效率也不高。這個時候你就須要一款利器,將字節碼轉換成java語言,從而你就能夠爲所欲爲的操縱字節碼。這些工具如ASM,例如Javaassit,BCEL等等,均可以用來操做字節碼。 而這裏我要介紹的就是操做字節碼的一把利器-ASM,ASM是一個java字節碼操縱框架,它能被用來動態生成類或者加強既有類的功能。ASM 能夠直接產生二進制 class 文件,也能夠在類被加載入 Java 虛擬機以前動態改變類行爲。Java class 被存儲在嚴格格式定義的 .class文件裏,這些類文件擁有足夠的元數據來解析類中的全部元素:類名稱、方法、屬性以及 Java 字節碼(指令)。ASM從類文件中讀入信息後,可以改變類行爲,分析類信息,甚至可以根據用戶要求生成新類。 ASM的優勢以下:web
在這個小標題我會簡單的介紹,如何去使用ASM。在這裏以前我但願你有idea編譯器,若是你有的話,能夠去插件庫裏面下載一個ASM Bytecode Outline。有了這個咱們後面開發ASM將會感覺到美滋滋,如魚得水。面試
ASM 庫供了兩個用於生成和轉換已編譯類的API,一個是核心API,以基於事件的形式來表示類,另外一個是樹API,以基於對象的形式來表示類。spring
沒有asm jar包的同窗須要引入下面的maven:編程
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>5.0.4</version>
</dependency>
複製代碼
這裏你們是否已經下好了那個插件(ASM Bytecode Outline)呢?若是下載完畢,還記得咱們上一節的那個例子嗎?json
public class ByteCodeDemo {
private static final String name = "xiaoming";
private int age;
public ByteCodeDemo(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(){
this.age = age;
}
public static void main(String[] args) {
ByteCodeDemo byteCodeDeomo = new ByteCodeDemo(12);
System.out.println("name:" + name + "age:" + byteCodeDeomo.getAge());
}
}
複製代碼
在這個類中,右鍵點擊下方後端
若是你看不懂,不要緊,我這裏會慢慢的講。api
在ASM的core API編程中有幾個關鍵類:bash
visitor是咱們擴展咱們類本身碼的關鍵架構
public static void main(String[] args) throws Exception {
FileInputStream fileInputStream = new FileInputStream("java/java8/ByteCodeDemo.class");
ClassReader classReader = new ClassReader(fileInputStream);
ClassWriter cw = new ClassWriter(classReader, ClassWriter.COMPUTE_MAXS);
//Java8選擇ASM5,
ClassVisitor classVisitor = new ClassVisitor(Opcodes.ASM5, cw) {
@Override
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
System.out.println("field:" + name);
return super.visitField(access, name, desc, signature, value);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
System.out.println("方法" + name);
return super.visitMethod(access, name, desc, signature, exceptions);
}
};
//忽略調試信息
classReader.accept(classVisitor, ClassReader.SKIP_DEBUG);
}
複製代碼
咱們下面輸出:
field:name
field:age
方法<init>
方法getAge
方法setAge
方法main
複製代碼
能夠看到咱們已經經過visitField和visitMethod,進行對每一個field和每一個Method的名字都進行了輸出,其中方法包括了編譯器幫咱們建立的構造方法和咱們自定義的三個方法。
因爲後面的代碼都會經過coreApi來作,這裏樹形API簡單用例子說明一下:
public static void main(String[] args) throws Exception {
FileInputStream fileInputStream = new FileInputStream("/Users/lizhao/Documents/RPC/test/src/main/java/java8/ByteCodeDemo.class");
ClassReader classReader = new ClassReader(fileInputStream);
ClassWriter cw = new ClassWriter(classReader, ClassWriter.COMPUTE_MAXS);
//忽略調試信息
ClassNode classNode = new ClassNode(org.objectweb.asm.Opcodes.ASM5);
classReader.accept(classNode, ClassReader.SKIP_DEBUG);
for (MethodNode methodNode:classNode.methods) {
System.out.println(methodNode.name);
}
classNode.accept(cw);
}
複製代碼
輸出以下:
<init>
getAge
setAge
main
複製代碼
本文簡單介紹了ASM的介紹,以及簡單的使用,下一章會介紹如何去用ASM作上一篇介紹的小工具,以及java的instrument機制。 同時想獲取ASM更多高級用法能夠關注個人公衆號回覆asm便可獲取。
因爲水平不足,若有錯誤還請批評與指正!
爲了方便你們學習交流,建了個qq java後端交流羣:837321192,裏面有我收藏的百G學習視頻(涵蓋面試,架構等等),也有不少面試資料,能夠加入進來一塊兒交流。
若是你們以爲這篇文章對你有幫助,或者想提早獲取後續章節文章,或者你有什麼疑問想提供1v1免費vip服務,均可以關注個人公衆號,關注便可免費領取上百G最新java學習資料視頻,以及最新面試資料,你的關注和轉發是對我最大的支持,O(∩_∩)O: