<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-314  評論-209  文章-0  trackbacks-0

    作者:薛谷雨

    作者簡介


    薛谷雨,NORDSAN(北京)信息科技開發有限公司高級JAVA研發工程師,正致力于企業級異構數據交換的服務器產品的研發,在J2EE和WEB SERVICE方面有較為豐富的開發經驗,您可以通過rainight@126.com與他聯系。

    前言


    代碼生成器(code generator,CG),顧名思義就是生成代碼的工具。有了它,你就可以從一組簡單的設定或者數據庫設計中獲得幾百、幾千行代碼。如果不采用這項技術的話,開發者就不得不花上幾個小時或者幾天的時間來手工編寫這些代碼。另一方面,優秀的開發工具為了提供其獨特的功能或者屏蔽一些容易出錯的細節,也往往采用代碼生成技術為使用者提供一個程序的模板框架,其目的也是為了提高編程的效率。以上觀點僅是對代碼生成器的一般理解,換句話說,這似乎是一個可有可無的東西,沒有它,不過是多費一些人工而已。然而,本文要介紹的這套名為ASM的JAVA工具類的功能非同小可,它可以生成JAVA字節碼,也就是class文件。你可以在應用程序中根據情況動態生成各式各樣的class,然后就調用,達到一種近乎上帝造物般的神奇。心動不如行動,如果你也想在自己的開發中引入這一超前的編程技術,請看此文。

    小巧而神奇的ASM


    ASM是一套JAVA字節碼生成架構。它可以動態生成二進制格式的stub類或其他代理類,或者在類被JAVA虛擬機裝入內存之前,動態修改類。ASM 提供了與 BCEL( http://jakarta.apache.org/bcel )和SERP( http://serp.sourceforge.net/ )相似的功能,只有22K的大小,比起350K的BCEL和150K的SERP來說,是相當小巧的,并且它有更高的執行效率,是BCEL的7倍,SERP的11倍以上。ASM一貫的設計思想就是將其應用于動態生成領域,因此小巧和快捷一直是這個產品的設計和實現的指導思想。

    此產品由法國電信公司的研發工程師Eric Bruneton負責。從2002年7月ASM的第一個版本發布至今,此產品已經升級了五次,日臻完美。到目前為止,ASM最新的版本是1.3.5,你可以去 http://asm.objectweb.org/ 下載。

    ASM的最終目標是創建一個生成工具,可以被用來執行對任何類的處理操作(不像一些工具,比如Javassit,它只支持預先定義的類操作,然而在許多場合這一功能是有局限性的)。

    JAVA的CLASS文件格式


    要想駕馭ASM,先要了解一下JAVA的CLASS文件格式。JAVA的CLASS文件通常是樹型結構。根節點包含以下元素:

    • ConstantPool:符號表;
    • FieldInfo:類中的成員變量信息;
    • MethodInfo:類中的方法描述;
    • Attribute:可選的附加節點。

    FieldInfo節點包含成員變量的名稱,諸如public,private,static等的標志。ConstantValue屬性用來存儲靜態的不變的成員變量的值。Deprecated和Synthetic被用來標記一個成員變量是不被推薦的或由編譯器生成的。

    MethodInfo節點包含方法的名稱,參數的類型和和它的返回值,方法是公有的,私有的或靜態的等標志。MethodInfo包含可選的附加屬性,其中最重要的是Code屬性,它包含非抽象的方法的代碼。Exceptions屬性包含方法將拋出的Exception的名稱。Deprecated和Synthetic屬性的信息同上面的FieldInfo的定義一樣。

    根節點的可選屬性有SourceFile,InnerClasses和Deprecated。SourceFile用來存儲被編譯成字節碼的源代碼文件的原始名稱;InnerClasses存儲內部類的信息。由于這些屬性的存在,java 的類格式是可以擴展的,也就是說可以在一個class中附加一些非標準的屬性, java虛擬機會忽略這些不可識別的屬性,正常的加載這個class。

    ConstantPool是一個由數字或字符串常量的索引組成的隊列,或由此類的樹的其他節點引用的,由其他對象創建的被引用常量的索引組成的隊列。這個表的目標是為了減少冗余。例如,FieldInfo節點不包含節點的名稱,只包含它在這一表中的索引。同樣的,GETFIELD和PUTFIELD不直接包含成員變量的名稱,只包含名稱的索引。

    精通ASM


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

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

    HelloWorld,體驗造類的神奇


    下面是一個應用ASM動態生成字節碼的類,并調用其中方法的完整的HelloWorld 程序,程序的功能是動態生成一個Example.class類,并實例化一個Example對象,調用對象的main函數,在屏幕上打印出"Hello world!"

    import org.objectweb.asm.*;
    import java.lang.reflect.*;
    import java.io.FileOutputStream;
    
    public class Helloworld extends ClassLoader implements Constants {
    
      public static void main (final String args[]) throws Exception {
    
        /*
         * 此程序將生成一個class,對應的java源代碼是:
         *
         * public class Example {
         *   public static void main (String[] args) {
         *     System.out.println("Hello world!");
         *   }
         * }
         *
         */
    
        // 創建一個ClassWriter
        ClassWriter cw = new ClassWriter(false);
        cw.visit(ACC_PUBLIC, "Example", "java/lang/Object", null, null);
    
        // 創建一個 MethodWriter
        CodeVisitor mw = cw.visitMethod(ACC_PUBLIC, "", "()V", null);
        // 推入 'this' 變量
        mw.visitVarInsn(ALOAD, 0);
        //  創建父類的構造函數
        mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V");
        mw.visitInsn(RETURN);
        // 這段代碼使用最多一個棧元素和一個本地變量
        mw.visitMaxs(1, 1);
    
        // 為main方法創建一個MethodWriter
        mw = cw.visitMethod(
          ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null);
        // 使用System類的out成員類
        mw.visitFieldInsn(
          GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
        // pushes the "Hello World!" String constant
        mw.visitLdcInsn("Hello world!");
        // 調用System.out的'println' 函數
        mw.visitMethodInsn(
          INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
        mw.visitInsn(RETURN);
        // 這段代碼使用最多兩個棧元素和兩個本地變量
        mw.visitMaxs(2, 2);
    
        // 生成字節碼形式的類
        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 main = exampleClass.getMethods()[0];
        main.invoke(null, new Object[] {null});
      }
    }
    
    posted on 2006-11-04 11:05 xzc 閱讀(441) 評論(0)  編輯  收藏 所屬分類: Java
    主站蜘蛛池模板: 成人免费视频软件网站| 久久免费的精品国产V∧| 亚洲色大成网站WWW久久九九| 久久久久女教师免费一区| 久久久久亚洲av无码专区导航| 日韩欧毛片免费视频| 男女猛烈无遮掩视频免费软件 | 国产亚洲精品高清在线| 亚洲国产超清无码专区| 皇色在线免费视频| 亚洲区小说区图片区QVOD| 在线v片免费观看视频| 特级毛片aaaa免费观看| 亚洲精品91在线| 亚洲国产一区明星换脸| 免费观看美女用震蛋喷水的视频| 精品国产亚洲一区二区三区在线观看| 亚洲精品乱码久久久久久蜜桃不卡| 在线视频精品免费| 精品人妻系列无码人妻免费视频| 亚洲国产成人91精品| 国产成人99久久亚洲综合精品| 91九色精品国产免费| 97超高清在线观看免费视频| 麻豆亚洲AV永久无码精品久久| 日韩精品视频免费在线观看| 男人的天堂网免费网站| 国产亚洲欧美在线观看| 亚洲综合视频在线观看| 亚洲人成影院在线观看| 成人免费看黄20分钟| 久久久久久国产精品免费无码| 无码毛片一区二区三区视频免费播放| 亚洲国产精品张柏芝在线观看| 亚洲午夜久久久久久久久电影网| 最近中文字幕mv免费高清视频8| 亚洲AV无码专区在线厂| 亚洲一级免费毛片| 亚洲第一页中文字幕| 亚洲AV区无码字幕中文色| 亚洲一区爱区精品无码|