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

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

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

    隨筆 - 14  文章 - 77  trackbacks - 0
    <2011年2月>
    303112345
    6789101112
    13141516171819
    20212223242526
    272812345
    6789101112

    常用鏈接

    留言簿(5)

    隨筆分類

    隨筆檔案

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    在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,都是基于這個核心的擴展。


             我們這里來看一下,如何讀寫字節碼


    ClassReader和ClassVisitor


             如大家所了解的,ASM是一個操作字節碼(bytecode)的框架,非常的小巧和快速,這個asm-3.3.1.jar,只有43k的大小。


             asm提供了字節碼的讀寫的功能。而asm的核心,采用的是visitor的模式,提供了ClassReader和ClassWriter這兩個非常重要的類以及ClassVisitor這個核心的接口。


             ClassReader的職責是讀取字節碼。可以用InputStream、byte數組、類名(需要ClassLoader.getSystemResourceAsStream能夠加載到的class文件)作為構造函數的參數構造ClassReader對象,來讀取字節碼。而ClassReader的工作,就是根據字節碼的規范,從輸入中讀取bytecode。而通過ClassReader對象,獲取bytecode信息有兩種方式,一種就是采用visitor的模式,傳入一個ClassVisitor對象給ClassReader的accept方法。另外一種,是使用Low Level的方式,使用ClassReader提供了readXXX以及getXXX的方法來獲取信息。


             對于一般使用,用ClassReader的accept方法,使用visitor模式就可以了。


             那么接著我們來看一下ClassVisitor。


             ClassVisitor這個接口,定義了一系列的visit方法,而這些visit方法,我們通過實現ClassVisitor接口中的visit方法(其實就是一堆的回調函數),就能夠得到相應的信息。


             在asm中,ClassAdapter這個類,用asm的javadoc上的話說,就是一個代理到其他ClassVisitor的一個空的ClassVisitor(An empty ClassVisitor that delegates to another ClassVisitor.)。具體來說,構造ClassAdapter對象的時候,需要傳遞一個ClassVisitor的對象給ClassAdapter的構造函數,而ClassAdapter對ClassVisitor的實現,就是直接調用這個傳給ClassAdapter的ClassVisitor對象的對應visit方法。


             后面我們會看到一個使用ClassAdapter的例子。


             說到這里,我們主要介紹了ClassReader這個類,ClassVisitor這個接口以及ClassAdapter。那么我們先看一個簡單的例子,是使用ClassReader和ClassVisitor的一個示例。


     1 package org.vanadies.bytecode.example.asm3;
     2 
     3 import java.io.IOException;
     4 
     5 import org.objectweb.asm.AnnotationVisitor;
     6 import org.objectweb.asm.Attribute;
     7 import org.objectweb.asm.ClassReader;
     8 import org.objectweb.asm.ClassVisitor;
     9 import org.objectweb.asm.FieldVisitor;
    10 import org.objectweb.asm.MethodVisitor;
    11 
    12 public class ClassReaderExample {
    13     private static class MyClassVisitor implements ClassVisitor {
    14 
    15         @Override
    16         public void visit(int version, int access, String name,
    17                 String signature, String superName, String[] interfaces) {
    18             System.out.println("class name:" + name);
    19             System.out.println("super class name:" + superName);
    20             System.out.println("class version:" + version);
    21             System.out.println("class access:" + access);
    22             System.out.println("class signature:" + signature);
    23             if(interfaces != null && interfaces.length > 0){
    24                 for(String str : interfaces){
    25                     System.out.println("implemented interface name:" + str);
    26                 }
    27             }
    28             
    29         }
    30 
    31         @Override
    32         public void visitSource(String source, String debug) {
    33         }
    34 
    35         @Override
    36         public void visitOuterClass(String owner, String name, String desc) {
    37         }
    38 
    39         @Override
    40         public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
    41             return null;
    42         }
    43 
    44         @Override
    45         public void visitAttribute(Attribute attr) {
    46         
    47         }
    48 
    49         @Override
    50         public void visitInnerClass(String name, String outerName,
    51                 String innerName, int access) {
    52         }
    53 
    54         @Override
    55         public FieldVisitor visitField(int access, String name, String desc,
    56                 String signature, Object value) {
    57             return null;
    58         }
    59 
    60         @Override
    61         public MethodVisitor visitMethod(int access, String name, String desc,
    62                 String signature, String[] exceptions) {
    63             return null;
    64         }
    65 
    66         @Override
    67         public void visitEnd() {
    68             
    69         }
    70     }
    71     
    72     public static void main(String args[]) throws IOException{
    73         ClassReader classReader = new ClassReader("java.lang.String");
    74         classReader.accept(new MyClassVisitor(), 0);
    75     }
    76 }

     

        這個簡單的例子,打印了String這個類的基本信息。


        從上面的例子看,ClassVisitor這個接口的方法中,有些返回值是void,有些是返回了XXXXVisitor。


        這里,返回XXXVisitor的,我們舉個例子,比如visitMethod這個方法,返回的是MethodVisitor。這里,在visitMethod的方法中,給出了Method的基本信息,如果需要去獲取Method內部的詳細的信息(包括代碼,注解等),那么需要返回一個MethodVisitor對象出去,如果返回null,那么在ClassReader中,就不會去展開對這個Method的詳細信息進行遍歷了。


        除了MethodVisitor,還有,AnnotationVisitor,FieldVisitor。


        另外,在org.objectweb.asm.signature這個包中,有一個SignatureVisitor以及SignatureReader和SignatureWriter,這個是處理Signature的。


        而除了ClassAdapter外還有MethodAdapter,作用類似與ClassAdapter,只是MethodAdapter是針對MethodVisitor的。


        到這里,我們已經了解了如何讀取bytecode的信息了,也了解了如何使用ClassReader和ClassVisitor了。 接下來,我們要看一下,如果使用ClassWriter這個類了。 ClassWriter,顧名思義,是用來寫字節碼的。ClassWriter實現了ClassVisitor這個接口。這里可能大家會覺得奇怪,ClassReader什么接口都沒有實現,為啥ClassWriter要實現ClassVisitor的接口呢?ClassWriter只要提供了方法,讓我寫字節碼就行了哇。


        大家還記得,通過ClassReader獲取類的字節碼,有兩種方式,一種是使用Visitor模式,這種方法很簡單,前面也有demo,另外是使用low level的get和read來進行,這個很復雜。而如果ClassWriter提供的是low level的put和write這類的方法,會提高門檻,很不好用。而ClassWriter實現了ClassVisitor接口,那么就能夠很好的跟ClassReader的Visitor模式結合起來。并且,我們使用ASM操作字節碼,在寫方面更多的是修改、添加和刪除,而不是用ASM來完全去寫新的class。


       ClassWriter中,還有一個toByteArray的方法,這個是把ClassWriter對象生成的字節碼,寫到一個byte數組中。用于我們來獲取字節碼的最終結果。


        那么,我們可以做一個很簡單的例子。就是把ClassWriter對象作為ClassReader accept方法的參數,傳給ClassReader,然后在accept方法結束后,我們用ClassWriter對象的toByteArray方法,就能夠獲得類的字節碼了。這個例子,就不貼源碼了,有興趣的同學,可以自己搞一下。


        那么,我們把ClassWriter用在哪里呢?上文提到了,刪除、修改、增加。那么一般來說,刪除我們是不太用的。主要是修改和增加。


        比方說我們如果自己要做AOP,用到的就是修改和增加。假如我有一個類,其中有一個execute方法,我如果自己做AOP,我可以把這個execute方法改名,比如叫做execute$1,然后我增加一個execute方法,新的execute方法中,我可以調用原來的execute方法(現在是execute$1)了,并且在調用前后做一個處理。


    我們來看一下具體代碼


     1 package org.vanadies.bytecode.example.asm3;
     2 
     3 import org.objectweb.asm.ClassAdapter;
     4 import org.objectweb.asm.ClassReader;
     5 import org.objectweb.asm.ClassWriter;
     6 import org.objectweb.asm.MethodVisitor;
     7 import org.objectweb.asm.Opcodes;
     8 
     9 public class ClassWriterAopExample {
    10     public static class Foo {
    11         public void execute(){
    12             System.out.println("Hello World");
    13         }
    14     }
    15     
    16     public static void main(String[] args) throws Exception{
    17         Foo foo = new Foo();
    18         foo.execute();
    19         ClassReader cr = new ClassReader(Foo.class.getName());
    20         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    21         cr.accept(new ClassAdapter(cw){
    22             @Override
    23             public void visit(
    24                     final int version,
    25                     final int access,
    26                     final String name,
    27                     final String signature,
    28                     final String superName,
    29                     final String[] interfaces)
    30                 {
    31                     cv.visit(version, access, name + "$1", signature, superName, interfaces);
    32                 }
    33 
    34             @Override
    35             public MethodVisitor visitMethod(
    36                     final int access,
    37                     final String name,
    38                     final String desc,
    39                     final String signature,
    40                     final String[] exceptions)
    41                 {
    42                     if("execute".equals(name)){
    43                         //這里只是簡單的比較了方法名字,其實還需要比較方法參數,參數信息在desc中
    44                         return cv.visitMethod(access, name + "$1", desc, signature, exceptions);
    45                     }
    46                     return cv.visitMethod(access, name, desc, signature, exceptions);
    47                 }
    48             
    49         }, 0);
    50         //到這里,如果調用cr.toByteArray,生成的字節碼中,已經沒有execute方法了,而是execute$1
    51         
    52         //我們接著需要增加一個execute方法
    53         MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "execute",
    54                 "()V"null,
    55                 null);
    56         //開始增加代碼
    57         mv.visitCode();
    58         //接下來,我們需要把新的execute方法的內容,增加到這個方法中
    59         mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System""out""Ljava/io/PrintStream;");
    60         mv.visitLdcInsn("Before execute");
    61         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream""println""(Ljava/lang/String;)V"); 
    62         mv.visitVarInsn(Opcodes.ALOAD, 0);
    63         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "org/vanadies/bytecode/example/asm3/ClassWriterAopExample$Foo$1""execute$1""()V");
    64         mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System""out""Ljava/io/PrintStream;");
    65         mv.visitLdcInsn("End execute");
    66         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream""println""(Ljava/lang/String;)V");
    67         mv.visitInsn(Opcodes.RETURN);
    68         mv.visitMaxs(00); //這個地方,最大的操作數棧和最大的本地變量的空間,是自動計算的,是因為構造ClassWriter的時候使用了ClassWriter.COMPUTE_MAXS
    69         mv.visitEnd();
    70         //到這里,就完成了execute方法的添加。
    71         //可以把字節碼寫入到文件,用javap -c,來看下具體的內容
    72     }
    73 }

     


    這個代碼,要比之前的ClassReader的例子要復雜一些。主要復雜的地方在重寫execute方法那里,其實就是類似在用匯編在寫代碼。具體怎么來寫或者生產這個代碼,有很多辦法。


    我們這里只是先展示一下如果能夠去修改字節碼。這個例子展示了,修改原有方法名字,以及增加方法的做法,其他的增加字段等,都可以通過ClassWriter來處理。另外,需要注意的是,在3.0的ASM中,構造函數的名字,一定要使


    用<init>,而不能使用“”,之前看到在2.x中,貌似有這樣的用法,但是沒有去驗證,在網上別人的例子中,也看到過methodName使用“”來表示構造函數的,這個在3.x中是不對的。


    具體在運行時能夠改變類的行為,我們可以通過Instrumentation的方式或者采用自己實現的ClassLoader的方式來處理。上面例子中,只是展示了如何修改字節碼,這個和實際在運行時達到AOP的效果,還是有距離的。

    posted on 2011-02-23 11:44 曾憲杰_頂天 閱讀(15043) 評論(0)  編輯  收藏 所屬分類: JVM

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 亚洲五月综合缴情在线观看| 亚洲成人免费网址| 亚洲日韩在线观看免费视频| 香蕉视频亚洲一级| 深夜a级毛片免费视频| 小说专区亚洲春色校园| 免费高清A级毛片在线播放| 日韩在线视频线视频免费网站| 美女视频黄视大全视频免费的| 美女视频黄a视频全免费网站一区| 四虎影视久久久免费观看| 一级做a爱过程免费视| 国产免费牲交视频免费播放| 精品人妻系列无码人妻免费视频 | 无码欧精品亚洲日韩一区夜夜嗨 | 亚洲精品mv在线观看 | 亚洲第一网站男人都懂| 亚洲AV永久无码精品一区二区国产 | 亚洲AV综合色区无码一二三区| 朝桐光亚洲专区在线中文字幕| 蜜芽亚洲av无码一区二区三区| 免费国产va在线观看| 你懂得的在线观看免费视频| 四虎影视成人永久免费观看视频| 亚洲一级免费视频| 永久免费AV无码网站在线观看| 亚洲国产一成久久精品国产成人综合| 亚洲真人无码永久在线| 亚洲男人天堂av| 亚洲欧美日韩中文高清www777| 成年网在线观看免费观看网址| 国产午夜成人免费看片无遮挡| 91麻豆国产免费观看| 成人看的午夜免费毛片| 免费一级毛片在级播放| 亚洲gv白嫩小受在线观看| 亚洲一卡二卡三卡四卡无卡麻豆| 激情无码亚洲一区二区三区| 97在线免费视频| 一个人在线观看视频免费| 免费午夜爽爽爽WWW视频十八禁 |