隨筆-35  評論-97  文章-0  trackbacks-0

          http://www.ibm.com/developerworks/cn/java/l-aspectJ/index.html中介紹了What is AspectJ 。

          1. AspectJ是一個代碼生成工具(Code Generator)。
          2. AspectJ語法就是用來定義代碼生成規則的語法。您如果使用過Java Compiler Compiler (JavaCC),您會發現,兩者的代碼生成規則的理念驚人相似。
          3. AspectJ有自己的語法編譯工具,編譯的結果是Java Class文件,運行的時候,classpath需要包含AspectJ的一個jar文件(Runtime lib)。
          4. ....

          看了上面幾點,我就想看看它怎么把代碼生成了。現在做一個試驗。

          一個類(包括main函數):Speaker.java

          package test.aspectj;

          public class Speaker
          {
              
          public void speak()
              
          {
                  System.out.println(
          "[Speaker] bla bla ");
              }


              
          public static void main(String[] args)
              
          {
                  Speaker speaker 
          = new Speaker();
                  speaker.speak();
              }

          }

           

          一個aspect:AspectObserver.aj

          package test.aspectj;

          public aspect AspectObserver
          {
              pointcut speakerSpeak():
                  call(
          void *Speaker.speak());
              before() : speakerSpeak() 
          {
                  System.out.println(
          "[AspectObserver] speaker is about to speak!");
              }

              after() returning() : speakerSpeak() 
          {
                  System.out.println(
          "[AspectObserver] speaker has completed his speech!");
              }

          }

          以上都是源碼部分哦。

          運行結果:

          [AspectObserver] speaker is about to speak!
          [Speaker] bla bla 
          [AspectObserver] speaker has completed his speech
          !

          說明程序是正常運作的哦。

          好了,下面,做三個操作:

          1、將以上的編譯成的class文件打包成apectjtest.jar文件。

                說明:可以使用ajdt的eclipse插件帶的導出功能,Export -->  JAR file with ApectJ support

          2、新建一個AspectJ工程,將apectjtest.jar加入類路徑,使用jad來反編譯Speaker.class和AspectObserver.class

           得到反編譯后的源碼:

          Speaker.class

          /*jadclipse*/// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
          // Jad home page: http://www.kpdus.com/jad.html
          // Decompiler options: packimports(3) radix(10) lradix(10) 
          // Source File Name:   Speaker.java

          package test.aspectj;

          import java.io.PrintStream;

          // Referenced classes of package test.aspectj:
          //            AspectObserver

          public class Speaker
          {

              
          public Speaker()
              
          {
              }


              
          public void speak()
              
          {
                  System.out.println(
          "[Speaker] bla bla ");
              }


              
          public static void main(String args[])
              
          {
                  Speaker speaker 
          = new Speaker();
                  AspectObserver.aspectOf().ajc$before$test_aspectj_AspectObserver$
          1$b2b6354();
                  speaker.speak();
                  AspectObserver.aspectOf().ajc$afterReturning$test_aspectj_AspectObserver$
          2$b2b6354();
              }

          }

           

          AspectObserver.class

          /*jadclipse*/// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
          // Jad home page: http://www.kpdus.com/jad.html
          // Decompiler options: packimports(3) radix(10) lradix(10) 
          // Source File Name:   AspectObserver.aj

          package test.aspectj;

          import java.io.PrintStream;
          import org.aspectj.lang.NoAspectBoundException;

          public class AspectObserver
          {

              
          public AspectObserver()
              
          {
              }


              
          void ajc$pointcut$$speakerSpeak$44()
              
          {
              }


              
          public void ajc$before$test_aspectj_AspectObserver$1$b2b6354()
              
          {
                  System.out.println(
          "[AspectObserver] speaker is about to speak!");
              }


              
          public void ajc$afterReturning$test_aspectj_AspectObserver$2$b2b6354()
              
          {
                  System.out.println(
          "[AspectObserver] speaker has completed his speech!");
              }


              
          public static AspectObserver aspectOf()
              
          {
                  
          if(ajc$perSingletonInstance == null)
                      
          throw new NoAspectBoundException("test_aspectj_AspectObserver", ajc$initFailureCause);
                  
          else
                      
          return ajc$perSingletonInstance;
              }


              
          public static boolean hasAspect()
              
          {
                  
          return ajc$perSingletonInstance != null;
              }


              
          private static void ajc$postClinit()
              
          {
                  ajc$perSingletonInstance 
          = new AspectObserver();
              }


              
          private static Throwable ajc$initFailureCause;
              
          public static final AspectObserver ajc$perSingletonInstance;

              
          static 
              
          {
                  
          try
                  
          {
                      ajc$postClinit();
                  }

                  
          catch(Throwable throwable)
                  
          {
                      ajc$initFailureCause 
          = throwable;
                  }

              }

          }

          3、運行一下Speaker.class

          得到結果:

          [AspectObserver] speaker is about to speak!
          [Speaker] bla bla 
          [AspectObserver] speaker has completed his speech
          !

           

          呵呵,結果跟源碼運行是一樣的哦(不一樣就是你的人品問題咯!!)

          分析一下,先理解AspectJ編譯器為我們做了什么事情:

          首先、AspectJ從文件列表里取出所有的文件名,然后讀取這些文件,進行分析。 
          二、AspectJ發現一些文件含有aspect的定義,在這個例子里,就是AspectObserver的定義;這些aspect就是代碼生成規則。 
          三、AspectJ根據這些aspect代碼生成規則,修改添加你的源代碼。在這個例子里,源碼是修改成怎樣了?比較一下反編譯后的代碼和源碼便知。 
          四、AspectJ讀取AspectObserver的定義,發現了一個pointcut
          --speakerSpeak();這個pointcut的定義是call(void *Speaker.speak()),表示所有對Speaker類的speak方法的執行點。 
          五、AspectJ繼續讀取AspectObserver的定義,發現了一個before(),這在AspectJ中叫做Advice。Advice允許你在某個類的方法的調用之前或調用之后,加入另外的代碼。加入的代碼是什么?比較一下反編譯后的代碼和源碼吧。 AspectJ繼續讀取AspectObserver的定義.

          好了,回頭看看反編譯后的Speaker.class,與源碼Speaker.java差別在哪呢?主要在main函數中,方法被調用的前后

              public static void main(String args[])
              
          {
                  Speaker speaker 
          = new Speaker();
                  AspectObserver.aspectOf().ajc$before$test_aspectj_AspectObserver$
          1$b2b6354();//多了這行
                  speaker.speak();
                  AspectObserver.aspectOf().ajc$afterReturning$test_aspectj_AspectObserver$
          2$b2b6354();//多了這行
              }

          不同的地方就是多出了兩行,雖然有$和數字,但是很容易看出,這同我們平常寫的java代碼差不了多少。

                  AspectObserver.aspectOf().ajc$before$test_aspectj_AspectObserver$1$b2b6354();

          這行代碼中,看起來不就是AspectObserver類調用了靜態方法aspectOf()嗎,接著aspectOf()的返回對象又調用ajc$before$test_aspectj_AspectObserver$1$b2b6354()方法嗎?

          回來看看AspectObserver.class的反編譯代碼,哈哈,這就對了,aspectOf返回的是AspectObserver的一個實例,返回實例在調用實例方法ajc$before$test_aspectj_AspectObserver$1$b2b6354()。ajc$before$test_aspectj_AspectObserver$1$b2b6354()是干什么的呢?呵呵,不正是我們要的攔截方法所要做的操作嗎?

          System.out.println("[AspectObserver] speaker is about to speak!");

          同樣,可知

           AspectObserver.aspectOf().ajc$afterReturning$test_aspectj_AspectObserver$2$b2b6354();

          是怎么一回事啦。

          這正是應了上面所提的兩點:

          1. AspectJ是一個代碼生成工具(Code Generator)。
          2. AspectJ語法就是用來定義代碼生成規則的語法。

          用這兩點去感受apectj在程序里該如何去運用使用,就清晰多啦!

          posted on 2007-07-12 01:12 三告習習 閱讀(5197) 評論(6)  編輯  收藏 所屬分類: AOP

          評論:
          # re: [AspectJ] 明明白白AspectJ (1) 2007-07-12 21:21 | ehe
          學習  回復  更多評論
            
          # re: [AspectJ] 明明白白AspectJ (1) 2007-07-19 21:02 | Danfo
          能不能講講spring代理實現aspectJ的機制呢?  回復  更多評論
            
          # re: [AspectJ] 明明白白AspectJ (1) 2007-07-19 21:40 | 三告習習
          @Danfo
          唉呀呀...苦惱時間少啊 :(
          快啦快啦  回復  更多評論
            
          # re: [AspectJ] 明明白白AspectJ (1) 2007-07-22 14:56 | 不長樹的葉子
          還是不知道  回復  更多評論
            
          # re: [AspectJ] 明明白白AspectJ (1) 2008-06-28 20:05 | moliqin
          鑒定完畢  回復  更多評論
            
          # re: [AspectJ] 明明白白AspectJ (1) 2012-07-02 11:55 | Hongxu Chen
          想問一下如果是用annotation語法生成的aspect和這里的方法在字節碼上有什么差異嗎?  回復  更多評論
            

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


          網站導航:
           
          主站蜘蛛池模板: 子长县| 五大连池市| 正阳县| 宾阳县| 乌兰浩特市| 江口县| 乐至县| 泾川县| 巫溪县| 文山县| 郑州市| 桐城市| 凤翔县| 中牟县| 策勒县| 揭西县| 庄河市| 陆川县| 铜陵市| 华池县| 嘉荫县| 日土县| 南皮县| 陆川县| 石屏县| 海晏县| 基隆市| 廊坊市| 西乌珠穆沁旗| 阿克| 鄯善县| 正蓝旗| 营口市| 友谊县| 鄂尔多斯市| 阳东县| 金坛市| 清苑县| 夹江县| 潜江市| 深州市|