asm 與 cglib(整理的)

參考博客地址html

http://www.oseye.net/user/kevin/blog/304#topjava

http://www.blogjava.net/vanadies10/archive/2011/02/23/344899.htmlweb

http://llying.iteye.com/blog/220452編程

http://www.cnblogs.com/liuling/archive/2013/05/21/CGlib-AOP.html數組

1 asm簡介服務器

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

目前許多框架如cglib、Hibernate、Spring都直接或間接地使用ASM操做字節碼,有些語言如Jython、JRuby、Groovy也是如此。而類ASM字節碼工具還有:工具

  1. BCEL:Byte Code Engineering Library (BCEL),這是Apache Software Foundation 的Jakarta 項目的一部分。BCEL是 Java classworking 最普遍使用的一種框架,它可讓您深刻 JVM 彙編語言進行類操做的細節。BCEL與Javassist 有不一樣的處理字節碼方法,BCEL在實際的JVM 指令層次上進行操做(BCEL擁有豐富的JVM 指令級支持)而Javassist 所強調的源代碼級別的工做。
  2. JBET:經過JBET(Java Binary Enhancement Tool )的API可對Class文件進行分解,從新組合,或被編輯。JBET也能夠建立新的Class文件。JBET用一種結構化的方式來展示Javabinary (.class)文件的內容,而且能夠很容易的進行修改。
  3. Javassist:Javassist是一個開源的分析、編輯和建立Java字節碼的類庫。是由東京技術學院的數學和計算機科學系的 Shigeru Chiba 所建立的。它已加入了開放源代碼JBoss 應用服務器項目,經過使用Javassist對字節碼操做爲JBoss實現動態AOP框架。
  4. cglib:是一個強大的,高性能,高質量的Code生成類庫。它能夠在運行期擴展Java類與實現Java接口,cglib封裝了asm,能夠在運行期動態生成新的 class,Hibernate和Spring都用到過它。cglib用於AOP,jdk中的proxy必須基於接口,cglib卻沒有這個限制。

而ASM與cglib、serp和BCEL相比,ASM有如下的優勢 :性能

  • ASM 具備簡單、設計良好的 API,這些 API 易於使用;
  • ASM 有很是良好的開發文檔,以及能夠幫助簡化開發的 Eclipse 插件;
  • ASM 支持 Java 6(ASM3)、Java7(ASM4)、Java(ASM5);
  • ASM 很小、很快、很健壯;
  • ASM 有很大的用戶羣,能夠幫助新手解決開發過程當中遇到的問題;
  • ASM 的開源許可可讓你幾乎以任何方式使用它;

2 asm jar包簡介編碼

  在ASM3.3.1中,提供了7個jar包,分別是

         asm-3.3.1.jar

         asm-commons-3.3.1.jar

   asm-tree-3.3.1.jar

         asm-analysis-3.3.1.jar

         asm-util-3.3.1.jar

         asm-xml-3.3.1.jar

 

         參看ASM的javadoc(http://asm.ow2.org/asm33/javadoc/user/index.html),能夠看到一共有7個package,package和jar的對應關係以下

    asm-3.3.1.jar 包含了org.objectweb.asm和org.objectweb.asm.signature兩個packages

     asm-commons-3.3.1.jar包含了org.objectweb.asm.commons這個package

     asm-tree-3.3.1.jar 包含了org.objectweb.asm.tree這個package

     asm-analysis-3.3.1.jar包含了org.objectweb.asm.tree.analysis這個package

     asm-util-3.3.1.jar包含了org.objectweb.asm.util這個package

        asm-xml-3.3.1.jar包含了org.objectweb.asm.xml這個package

        其中asm-3.3.1.jar,是包含了核心的功能,而其餘的jar,都是基於這個核心的擴展。

 

3  Java字節碼文件

所謂 Java 字節碼文件,就是一般用 javac 編譯器產生的 .class 文件。這些文件具備嚴格定義的格式。爲了更好的理解 ASM,首先對 Java 字節碼文件格式做一點簡單的介紹。Java 源文件通過 javac 編譯器編譯以後,將會生成對應的二進制文件(以下圖所示)。每一個合法的 Java 字節碼文件都具有精確的定義,而正是這種精確的定義,才使得 Java 虛擬機得以正確讀取和解釋全部的 Java 字節碼文件。

Java 字節碼文件是 8 位字節的二進制流。數據項按順序存儲在 class 文件中,相鄰的項之間沒有間隔,這使得 class 文件變得緊湊,減小存儲空間。在 Java 字節碼文件中包含了許多大小不一樣的項,因爲每一項的結構都有嚴格規定,這使得 class 文件可以從頭至尾被順利地解析。下面讓咱們來看一下 Java 字節碼文件的內部結構,以便對此有個大體的認識。

例如,一個最簡單的 Hello World 程序:

  1. public class HelloWorld {
  2. public static void main(String[] args) {
  3. System.out.println("Hello world");
  4. }
  5. }

從上圖中能夠看到,一個 Java 字節碼文件大體能夠歸爲 10 個項:

  • Magic:該項存放了一個 Java 字節碼文件的魔數(magic number)和版本信息。一個 Java 字節碼文件的前 4 個字節被稱爲它的魔數。每一個正確的 Java 字節碼文件都是以 0xCAFEBABE 開頭的,這樣保證了 Java 虛擬機能很輕鬆的分辨出 Java 文件和非 Java 文件。
  • Version:該項存放了 Java 字節碼文件的版本信息,它對於一個 Java 文件具備重要的意義。由於 Java 技術一直在發展,因此字節碼文件的格式也處在不斷變化之中。字節碼文件的版本信息讓虛擬機知道如何去讀取並處理該字節碼文件。
  • Constant Pool:該項存放了類中各類文字字符串、類名、方法名和接口名稱、final 變量以及對外部類的引用信息等常量。虛擬機必須爲每個被裝載的類維護一個常量池,常量池中存儲了相應類型所用到的全部類型、字段和方法的符號引用,所以它在 Java 的動態連接中起到了核心的做用。常量池的大小平均佔到了整個類大小的 60% 左右。
  • Access_flag:該項指明瞭該文件中定義的是類仍是接口(一個 class 文件中只能有一個類或接口),同時還指名了類或接口的訪問標誌,如 public,private, abstract 等信息。
  • This Class:指向表示該類全限定名稱的字符串常量的指針。
  • Super Class:指向表示父類全限定名稱的字符串常量的指針。
  • Interfaces:一個指針數組,存放了該類或父類實現的全部接口名稱的字符串常量的指針。以上三項所指向的常量,特別是前兩項,在咱們用 ASM 從已有類派生新類時通常須要修改:將類名稱改成子類名稱;將父類改成派生前的類名稱;若是有必要,增長新的實現接口。
  • Fields:該項對類或接口中聲明的字段進行了細緻的描述。須要注意的是,fields 列表中僅列出了本類或接口中的字段,並不包括從超類和父接口繼承而來的字段。
  • Methods:該項對類或接口中聲明的方法進行了細緻的描述。例如方法的名稱、參數和返回值類型等。須要注意的是,methods 列表裏僅存放了本類或本接口中的方法,並不包括從超類和父接口繼承而來的方法。使用 ASM 進行 AOP 編程,一般是經過調整 Method 中的指令來實現的。
  • Class attributes:該項存放了在該文件中類或接口所定義的屬性的基本信息。

事實上,使用 ASM 動態生成類,不須要像早年的 class hacker 同樣,熟知 class 文件的每一段,以及它們的功能、長度、偏移量以及編碼方式。ASM 會給咱們照顧好這一切的,咱們只要告訴 ASM 要改動什麼就能夠了 —— 固然,咱們首先得知道要改什麼:對字節碼文件格式瞭解的越多,咱們就能更好地使用 ASM 這個利器。

ASM編程模型

ASM 提供了兩種編程模型:

  • Core API,提供了基於事件形式的編程模型。該模型不須要一次性將整個類的結構讀取到內存中,所以這種方式更快,須要更少的內存。但這種編程方式難度較大。
  • Tree API,提供了基於樹形的編程模型。該模型須要一次性將一個類的完整結構所有讀取到內存當中,因此這種方法須要更多的內存。這種編程方式較簡單。

Core API 中操縱字節碼的功能基於 ClassVisitor 接口。這個接口中的每一個方法對應了 class 文件中的每一項。Class 文件中的簡單項的訪問使用一個單獨的方法,方法參數描述了這個項的內容。而那些具備任意長度和複雜度的項,使用另一類方法,這類方法會返回一個輔助的 Visitor 接口,經過這些輔助接口的對象來完成具體內容的訪問。例如 visitField 方法和 visitMethod 方法,分別返回 FieldVisitor 和 MethodVisitor 接口的對象。

ASM 提供了三個基於 ClassVisitor 接口的類來實現 class 文件的生成和轉換:

  • ClassReader:ClassReader 解析一個類的 class 字節碼,該類的 accept 方法接受一個 ClassVisitor 的對象,在 accept 方法中,會按上文描述的順序逐個調用 ClassVisitor 對象的方法。它能夠被看作事件的生產者。
  • ClassAdapter:ClassAdapter 是 ClassVisitor 的實現類。它的構造方法中須要一個 ClassVisitor 對象,並保存爲字段 protected ClassVisitor cv。在它的實現中,每一個方法都是原封不動的直接調用 cv 的對應方法,並傳遞一樣的參數。能夠經過繼承 ClassAdapter 並修改其中的部分方法達到過濾的做用。它能夠看作是事件的過濾器。
  • ClassWriter:ClassWriter 也是 ClassVisitor 的實現類。ClassWriter 能夠用來以二進制的方式建立一個類的字節碼。對於 ClassWriter 的每一個方法的調用會建立類的相應部分。例如:調用 visit 方法就是建立一個類的聲明部分,每調用一次 visitMethod 方法就會在這個類中建立一個新的方法。在調用 visitEnd 方法後即代表該類的建立已經完成。它最終生成一個字節數組,這個字節數組中包含了一個類的 class 文件的完整字節碼內容 。能夠經過 toByteArray 方法獲取生成的字節數組。ClassWriter 能夠看作事件的消費者

5 ASMifer 工具

  直接編碼ASM其實對於新手來講是很困難的事,但幸運的是ASM給咱們提供了ASMifer工具。通常咱們會使用ASM的ASMifer工具生成ASM結構來對比,使用命令:

  1. java org.objectweb.asm.util.ASMifier net.oseye.demoasm.HelloWorld

6 例子:參考地址

  http://www.blogjava.net/vanadies10/archive/2011/02/23/344899.html

  http://llying.iteye.com/blog/220452

  http://www.cnblogs.com/liuling/archive/2013/05/21/CGlib-AOP.html

  代碼 : 

相關文章
相關標籤/搜索