ASM第一篇【HelloWorld】

簡介:ASM 是一個 Java 字節碼操控框架。它能被用來動態生成類或者增強既有類的功能。ASM 可以直接產生二進制 class 文件,也可以在類被加載入 Java 虛擬機之前動態改變類行爲。Java class 被存儲在嚴格格式定義的 .class 文件裏,這些類文件擁有足夠的元數據來解析類中的所有元素:類名稱、方法、屬性以及 Java 字節碼(指令)。ASM 從類文件中讀入信息後,能夠改變類行爲,分析類信息,甚至能夠根據用戶要求生成新類。

Asm架構整體都圍繞着兩個接口,即ClassVisitor 和 CodeVisitor,它們能訪問每個類的方法,成員變量,包含在每個方法中的字節碼指令。ClassReader用來讀取class文件;ClassWriter類用來寫生成的Class文件。

爲了修改已經存在的class,你必須使用分析class文件的ClassReader,類的修正器和寫class文件的ClassWriter。 類的修正器就是一個ClassVisitor,它可以委派一部分工作到其他的ClassVisitor,但是爲了實現預期的修改步驟,它將改變一些參數的 值,或者調用一些其他方法。爲了比較容易的實現這種類的修正器,ASM提供了一個ClassAdapter和CodeAdapter,這兩個適配器類分別 實現了ClassVistor和CodeVistor接口。

ASM官網:http://asm.ow2.org/

ASM最新版本是4.0 下載地址:http://forge.ow2.org/projects/asm/

學習ASM最好能下載ASM的一個eclipse的插件,這個插件能看你當前類如果用ASM來生成代碼應該怎樣寫。插件下載地址:http://download.forge.objectweb.org/eclipse-update/

 

下面用ASM寫一個HelloWorld,體驗一下哈。

import java.io.FileOutputStream;
import java.lang.reflect.Method;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
public class HelloWorld extends ClassLoader {
 /**
  * 如何使用ASM動態生成一個類,並打印出HelloWorld!
  * 
  * @param args
  * @throws Exception
  */
 public static void main(String[] args) throws Exception {
  // 創建一個ClassWriter來寫示例類,這個類繼承Object
  ClassWriter cw = new ClassWriter(0);
  /*
   * 第一個參數:JDK版本 
   * 第二個參數:這個類的訪問標記 
   * 第三個參數:這個類的名字
   * 第四個參數:這個類的簽名,當這個類沒有繼承或者實現一個接口的時候可以爲空。 
   * 第五個參數:當前類父類的名字 接口的父類是Object當該類是Object的時候爲空 
   * 第六個參數:接口的名字 可以爲空
   */
  cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC, "Example", null, "java/lang/Object", null);
  /*
   * 創建一個寫默認構造器的MethodWriter 
   * 第一個參數:方法的訪問標記 
   * 第二個參數:方法名稱 
   * 第三個參數:方法的描述符號
   * 第四個參數:方法簽名(當方法參數 返回類型 以及異常沒有用到類屬性的時候可以爲空) 
   * 第⑤個參數:異常名稱
   */
  MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
  // 壓入this變量
  mv.visitVarInsn(Opcodes.ALOAD, 0);
  // 執行父類構造器
  mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
  mv.visitInsn(Opcodes.RETURN);
  // 這段代碼使用最多一個堆元素 和一個 局部變量
  mv.visitMaxs(1, 1);
  mv.visitEnd();
  // 創建一個main方法的MethodWriter
  mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
  // 調用System類的PrintStream類的out
  mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
  // 壓入"Hello World!" 常量
  mv.visitLdcInsn("Hello World!");
  // 執行定義在PrintStream中的println方法
  mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
  mv.visitInsn(Opcodes.RETURN);
  // 使用兩個堆和兩個局部變量
  mv.visitMaxs(2, 2);
  // 獲取Example類的字節碼並且動態加載它。
  byte[] code = cw.toByteArray();
  FileOutputStream fos = new FileOutputStream("Example.class");
  fos.write(code);
  fos.close();
  HelloWorld loader = new HelloWorld();
  Class<?> exampleClass = loader.defineClass("Example", code, 0, code.length);
  // 使用動態生成的類打印HelloWorld
  Method method = exampleClass.getMethods()[0];
  method.invoke(null, new Object[] { null });
 }
}

 

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