隨筆-35  評(píng)論-97  文章-0  trackbacks-0

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

          1. AspectJ是一個(gè)代碼生成工具(Code Generator)。
          2. AspectJ語(yǔ)法就是用來(lái)定義代碼生成規(guī)則的語(yǔ)法。您如果使用過(guò)Java Compiler Compiler (JavaCC),您會(huì)發(fā)現(xiàn),兩者的代碼生成規(guī)則的理念驚人相似。
          3. AspectJ有自己的語(yǔ)法編譯工具,編譯的結(jié)果是Java Class文件,運(yùn)行的時(shí)候,classpath需要包含AspectJ的一個(gè)jar文件(Runtime lib)。
          4. ....

          看了上面幾點(diǎn),我就想看看它怎么把代碼生成了。現(xiàn)在做一個(gè)試驗(yàn)。

          一個(gè)類(包括main函數(shù)):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();
              }

          }

           

          一個(gè)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!");
              }

          }

          以上都是源碼部分哦。

          運(yùn)行結(jié)果:

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

          說(shuō)明程序是正常運(yùn)作的哦。

          好了,下面,做三個(gè)操作:

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

                說(shuō)明:可以使用ajdt的eclipse插件帶的導(dǎo)出功能,Export -->  JAR file with ApectJ support

          2、新建一個(gè)AspectJ工程,將apectjtest.jar加入類路徑,使用jad來(lái)反編譯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、運(yùn)行一下Speaker.class

          得到結(jié)果:

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

           

          呵呵,結(jié)果跟源碼運(yùn)行是一樣的哦(不一樣就是你的人品問(wèn)題咯!!)

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

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

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

              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();//多了這行
              }

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

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

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

          回來(lái)看看AspectObserver.class的反編譯代碼,哈哈,這就對(duì)了,aspectOf返回的是AspectObserver的一個(gè)實(shí)例,返回實(shí)例在調(diào)用實(shí)例方法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();

          是怎么一回事啦。

          這正是應(yīng)了上面所提的兩點(diǎn):

          1. AspectJ是一個(gè)代碼生成工具(Code Generator)。
          2. AspectJ語(yǔ)法就是用來(lái)定義代碼生成規(guī)則的語(yǔ)法。

          用這兩點(diǎn)去感受apectj在程序里該如何去運(yùn)用使用,就清晰多啦!

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

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

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 黑龙江省| 晋宁县| 商洛市| 武定县| 句容市| 绥宁县| 白朗县| 海林市| 高唐县| 贵阳市| 泰顺县| 林甸县| 定西市| 璧山县| 池州市| 长海县| 游戏| 淳化县| 芜湖县| 华亭县| 阳山县| 嘉兴市| 七台河市| 甘孜| 商丘市| 尚义县| 福建省| 公安县| 敦煌市| 巩留县| 商丘市| 屏山县| 时尚| 城固县| 曲水县| 甘孜县| 普格县| 社旗县| 江山市| 广丰县| 长春市|