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

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

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

    Sealyu

    --- 博客已遷移至: http://www.sealyu.com/blog

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      618 隨筆 :: 87 文章 :: 225 評論 :: 0 Trackbacks
    在jdk5.0版本中,添加了一個新的接口java.lang.instrument.Instrumentation,這個接口可以用來在類加載的時候 對類的字節碼進行修改,改變類的功能的實現。通過這種方法,我們就可以實現aop的功能,這是和proxy動態代理的不同的另一種aop的實現。
         這種方法的原理很簡單,就是通過修改編譯器已經編譯好的字節碼來修改類,和我們通常修改類源碼來實現對類的修改差不多。只不過是在兩個不同的層次進行的修改。
         一下是使用這個接口的具體方法。
        第一步:
        需要實現  java.lang.instrument.Instrumentation這個接口,通過在這個接口的實現類中,在加載類的時候修改類的字節碼。以下是接口的實現 Transformer.java
    public class Transformer implements ClassFileTransformer {
       //在程序運行之前就被jvm調用的方法
       public static void premain(String args, Instrumentation inst) {
            inst.addTransformer(new Transformer());
        }
        public byte[] transform(ClassLoader loader, String className,
                Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
                byte[] classfileBuffer) throws IllegalClassFormatException {
            byte[] result =null; //定義新的字節碼存儲變量
            //在此通過修改類的字節碼 classfileBuffer,來更改類。
            return result; //返回新的字節碼
        }
    }
    第二步:
    需要將
    Transformer類的class文件生成jar文件,如t.jar,在jar文件的MANIFEST.MF添加 Premain-Class: Transformer 這一項。在運行程序時,需要在jvm使用如下參數 -javaagent:t.jar 。這樣jvm在運行時,就會先找到Premain-Class: Transformer  這一項指定的Transformer類的premain方法,運行此方法。也就實現了在以后的類的加載中,對類的字節碼進行修改的功能。

            就是使用
    java.lang.instrument.Instrumentation接口的方法。那么如何實現aop功能呢,這就需要在更改字節碼的時候,在類的功能上添加aop方面的功能。
           現在我們看看如何實現在方法的調用前和返回時打印當前時間的aop功能。
          先更改Transformer的transform方法
    public byte[] transform(ClassLoader loader, String className,
                Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
                byte[] classfileBuffer) throws IllegalClassFormatException {
            byte[] result =classfileBuffer; //定義新的字節碼存儲變量
            //在此通過修改類的字節碼 classfileBuffer,來更改類。
            if (loader != ClassLoader.getSystemClassLoader()) {
                return classfileBuffer;
            }

            ClassReader reader = new ClassReader(classfileBuffer);
            ClassWriter writer = new ClassWriter(true);
            ClassAdapter adapter = new PerfClassAdapter(writer, className);
            reader.accept(adapter, true);
            result = writer.toByteArray();
            return result; //返回新的字節碼
        }

    這樣就通過PerfClassAdapter類來修改字節碼.
    PerfClassAdapter.java
    public class PerfClassAdapter extends ClassAdapter {
        private String className;
        public PerfClassAdapter(ClassVisitor visitor, String theClass) {
            super(visitor);
            this.className = theClass;
        }
        public MethodVisitor visitMethod(int arg,
                String name,
                String descriptor,
                String signature,
                String[] exceptions) {
            MethodVisitor mv = super.visitMethod(arg,
                    name,
                    descriptor,
                    signature,
                    exceptions);
            MethodAdapter ma = new PerfMethodAdapter(mv, className, name);
            return ma;
        } 
    }
    PerfMethodAdapter.java
    public class PerfMethodAdapter extends MethodAdapter {
        private String _className, _methodName;
       
        public PerfMethodAdapter(MethodVisitor visitor,
                String className,
                String methodName) {
            super(visitor);
            _className = className;
            _methodName = methodName;
        }

        public void visitCode() {
            this.visitLdcInsn(_className);
            this.visitLdcInsn(_methodName);
            this.visitMethodInsn(INVOKESTATIC,
                    "
    AOP_LOG",
                    "start",
                    "(Ljava/lang/String;Ljava/lang/String;)V");
            super.visitCode();
        }

        public void visitInsn(int inst) {
            switch (inst) {
            case Opcodes.ARETURN:
            case Opcodes.DRETURN:
            case Opcodes.FRETURN:
            case Opcodes.IRETURN:
            case Opcodes.LRETURN:
            case Opcodes.RETURN:
            case Opcodes.ATHROW:
                this.visitLdcInsn(_className);
                this.visitLdcInsn(_methodName);
                this.visitMethodInsn(INVOKESTATIC,
                        "AOP_LOG",
                        "end",
                        "(Ljava/lang/String;Ljava/lang/String;)V");
                break;
            default:
                break;
            }
            super.visitInsn(inst);
        }
    }
    AOP_LOG.java
    public class
    AOP_LOG{
       
        public static void start(String className, String methodName) {
            System.out.println(new StringBuilder(className)
                    .append('"t')
                    .append(methodName)
                    .append(""tstart"t")
                    .append(System.currentTimeMillis()));       
        }
        public static void end(String className, String methodName) {
            System.out.println(new StringBuilder(className)
                    .append('"t')
                    .append(methodName)
                    .append(""tend"t")
                    .append(System.currentTimeMillis()));       
        }
    }
    這些類結合起來,就實現了在方法的調用前,會調用
    AOP_LOG類的start方法,在方法返回后,調用AOP_LOG類的end方法。

    現在寫個測試類來測試一下。
    TSMain.java
    public class TSMain {

        public static void main(String[] args) {
            TSMain tsm = new TSMain();
            tsm.printClassName();
        }
       
        public void printClassName(){
            System.out.println("hello "+this.getClass().getName());
        }
    }

    運行命令如下:
    =>java -javaagent:t.jar  classpath cpdir TSMain  #
    cpdir 需要用到的類的路徑

    輸出結果如下:
    TSMain    main    start    1179374205562
    TSMain    <init>    start    1179374205562
    TSMain    <init>    end    1179374205562
    TSMain    printClassName    start    1179374205562
    hello TSMain
    TSMain    printClassName    end    1179374205562
    TSMain    main    end    1179374205562


    到這里就完成整個aop的功能實現了。需要補充說明的是,這里修改類的字節碼是使用了asm的基礎類庫,所以需要導入這些asm的jar文件。
    posted on 2008-04-10 22:30 seal 閱讀(555) 評論(0)  編輯  收藏 所屬分類: Java基礎
    主站蜘蛛池模板: 日韩a级毛片免费观看| 天天影视色香欲综合免费| 国产美女精品久久久久久久免费| 国产精品免费无遮挡无码永久视频| 99re6热视频精品免费观看| 国产成在线观看免费视频| 亚洲国产成人a精品不卡在线| 国产A在亚洲线播放| a毛片全部免费播放| 亚洲热线99精品视频| 免费无码又爽又刺激网站| 午夜时刻免费入口| 亚洲一区精彩视频| 成人爽a毛片免费| 午夜色a大片在线观看免费| 久久久久亚洲国产| 国产成人综合久久精品免费| 国产AV无码专区亚洲A∨毛片| 亚洲欧洲av综合色无码| 女人18毛片a级毛片免费| 极品色天使在线婷婷天堂亚洲| 精品无码人妻一区二区免费蜜桃| 亚洲精品无码av天堂| 久久久受www免费人成| 日韩精品亚洲人成在线观看| 成人性生交大片免费看午夜a| 久久久亚洲欧洲日产国码aⅴ| 久久国产精品免费一区| 久久国产精品亚洲综合| 一二三四免费观看在线电影| 亚洲黄色三级网站| 成人免费无码大片a毛片| 精品亚洲成a人片在线观看少妇| 夜夜爽妓女8888视频免费观看| 成人a视频片在线观看免费| 337p欧洲亚洲大胆艺术| 免费无码看av的网站| 亚洲 欧洲 自拍 另类 校园| 三上悠亚电影全集免费| 亚洲va久久久噜噜噜久久天堂| 春意影院午夜爽爽爽免费|