zoukankan      html  css  js  c++  java
  • AspectJ本质剖析

    AOP一共有两种方式,spring默认使用的是动态代理(JDK自带的动态代理或者使用cglib的动态代理)和静态代理(ASPECTJ)

    http://blog.csdn.net/zhao9tian/article/details/37762389

    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

    [java] view plain copy
     
    1. package test.aspectj;  
    2.   
    3. public class Speaker  
    4. {  
    5.     public void speak()  
    6.     {  
    7.         System.out.println("[Speaker] bla bla ");  
    8.     }  
    9.     public static void main(String[] args)  
    10.     {  
    11.         Speaker speaker = new Speaker();  
    12.         speaker.speak();  
    13.     }  
    14. }  

    一个aspect:AspectObserver.java

    [java] view plain copy
     
    1. package test.aspectj;  
    2.   
    3. public aspect AspectObserver  
    4. {  
    5.     pointcut speakerSpeak():  
    6.         call(void *Speaker.speak());  
    7.     before() : speakerSpeak() {  
    8.         System.out.println("[AspectObserver] speaker is about to speak!");  
    9.     }  
    10.     after() returning() : speakerSpeak() {  
    11.         System.out.println("[AspectObserver] speaker has completed his speech!");  
    12.     }  
    13. }  

    以上都是源码部分哦。

    运行结果:

    [java] view plain copy
     
    1. [AspectObserver] speaker is about to speak!  
    2. [Speaker] bla bla   
    3. [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

    [java] view plain copy
     
    1. /*jadclipse*/// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.  
    2. // Jad home page: http://www.kpdus.com/jad.html  
    3. // Decompiler options: packimports(3) radix(10) lradix(10)   
    4. // Source File Name:   Speaker.java  
    5.   
    6. package test.aspectj;  
    7.   
    8. import java.io.PrintStream;  
    9.   
    10. // Referenced classes of package test.aspectj:  
    11. //            AspectObserver  
    12.   
    13. public class Speaker  
    14. {  
    15.   
    16.     public Speaker()  
    17.     {  
    18.     }  
    19.   
    20.     public void speak()  
    21.     {  
    22.         System.out.println("[Speaker] bla bla ");  
    23.     }  
    24.   
    25.     public static void main(String args[])  
    26.     {  
    27.         Speaker speaker = new Speaker();  
    28.         AspectObserver.aspectOf().ajc$before$test_aspectj_AspectObserver$1$b2b6354();  
    29.         speaker.speak();  
    30.         AspectObserver.aspectOf().ajc$afterReturning$test_aspectj_AspectObserver$2$b2b6354();  
    31.     }  
    32. }  

    AspectObserver.class

    [java] view plain copy
     
    1. /*jadclipse*/// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.  
    2. // Jad home page: http://www.kpdus.com/jad.html  
    3. // Decompiler options: packimports(3) radix(10) lradix(10)   
    4. // Source File Name:   AspectObserver.aj  
    5.   
    6. package test.aspectj;  
    7.   
    8. import java.io.PrintStream;  
    9. import org.aspectj.lang.NoAspectBoundException;  
    10.   
    11. public class AspectObserver  
    12. {  
    13.   
    14.     public AspectObserver()  
    15.     {  
    16.     }  
    17.   
    18.     void ajc$pointcut$$speakerSpeak$44()  
    19.     {  
    20.     }  
    21.   
    22.     public void ajc$before$test_aspectj_AspectObserver$1$b2b6354()  
    23.     {  
    24.         System.out.println("[AspectObserver] speaker is about to speak!");  
    25.     }  
    26.   
    27.     public void ajc$afterReturning$test_aspectj_AspectObserver$2$b2b6354()  
    28.     {  
    29.         System.out.println("[AspectObserver] speaker has completed his speech!");  
    30.     }  
    31.   
    32.     public static AspectObserver aspectOf()  
    33.     {  
    34.         if(ajc$perSingletonInstance == null)  
    35.             throw new NoAspectBoundException("test_aspectj_AspectObserver", ajc$initFailureCause);  
    36.         else  
    37.             return ajc$perSingletonInstance;  
    38.     }  
    39.   
    40.     public static boolean hasAspect()  
    41.     {  
    42.         return ajc$perSingletonInstance != null;  
    43.     }  
    44.   
    45.     private static void ajc$postClinit()  
    46.     {  
    47.         ajc$perSingletonInstance = new AspectObserver();  
    48.     }  
    49.   
    50.     private static Throwable ajc$initFailureCause;  
    51.     public static final AspectObserver ajc$perSingletonInstance;  
    52.   
    53.     static   
    54.     {  
    55.         try  
    56.         {  
    57.             ajc$postClinit();  
    58.         }  
    59.         catch(Throwable throwable)  
    60.         {  
    61.             ajc$initFailureCause = throwable;  
    62.         }  
    63.     }  
    64. }  

    3、运行一下Speaker.class

    得到结果:

    [java] view plain copy
     
    1. [AspectObserver] speaker is about to speak!  
    2. [Speaker] bla bla   
    3. [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函数中,方法被调用的前后

    [java] view plain copy
     
    1. public static void main(String args[])  
    2. {  
    3.     Speaker speaker = new Speaker();  
    4.     AspectObserver.aspectOf().ajc$before$test_aspectj_AspectObserver$1$b2b6354();//多了这行  
    5.     speaker.speak();  
    6.     AspectObserver.aspectOf().ajc$afterReturning$test_aspectj_AspectObserver$2$b2b6354();//多了这行  
    7. }  

    不同的地方就是多出了两行,虽然有$和数字,但是很容易看出,这同我们平常写的java代码差不了多少。

    [java] view plain copy
     
    1. 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()是干什么的呢?呵呵,不正是我们要的拦截方法所要做的操作吗?

    [java] view plain copy
     
    1. System.out.println("[AspectObserver] speaker is about to speak!");  

    同样,可知

    [java] view plain copy
     
    1. AspectObserver.aspectOf().ajc$afterReturning$test_aspectj_AspectObserver$2$b2b6354();  

    是怎么一回事啦。

    这正是应了上面所提的两点:

    1. AspectJ是一个代码生成工具(Code Generator)。
    2. AspectJ语法就是用来定义代码生成规则的语法。

    用这两点去感受apectj在程序里该如何去运用使用,就清晰多啦!

  • 相关阅读:
    线性表算法设计题2.11
    硬币抛掷模拟(使用数组)
    循环列示例(约瑟夫环问题)
    线性表算法设计题2.15
    ASP.NET2.0中的GRIDVIEW控件在使用TemplateField中的LinkButton时如何在RowCommand事件中找到当前行index的方法
    VS2005发布网站问题及"aspnet_merge.exe”已退出,代码为 1的错误
    弹出对话框的同时保持页面的显示(不变形)
    NET Framework 类库
    一些实用的正则表达式
    CuteEditor6.0使用配置心得体会
  • 原文地址:https://www.cnblogs.com/YDDMAX/p/5378568.html
Copyright © 2011-2022 走看看