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

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

一个aspect:AspectObserver.java

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

以上都是源码部分哦。

运行结果:

  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

  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. package test.aspectj;
  6. import java.io.PrintStream;
  7. // Referenced classes of package test.aspectj:
  8. //            AspectObserver
  9. public class Speaker
  10. {
  11. public Speaker()
  12. {
  13. }
  14. public void speak()
  15. {
  16. System.out.println("[Speaker] bla bla ");
  17. }
  18. public static void main(String args[])
  19. {
  20. Speaker speaker = new Speaker();
  21. AspectObserver.aspectOf().ajc$before$test_aspectj_AspectObserver$1$b2b6354();
  22. speaker.speak();
  23. AspectObserver.aspectOf().ajc$afterReturning$test_aspectj_AspectObserver$2$b2b6354();
  24. }
  25. }

AspectObserver.class

  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. package test.aspectj;
  6. import java.io.PrintStream;
  7. import org.aspectj.lang.NoAspectBoundException;
  8. public class AspectObserver
  9. {
  10. public AspectObserver()
  11. {
  12. }
  13. void ajc$pointcut$$speakerSpeak$44()
  14. {
  15. }
  16. public void ajc$before$test_aspectj_AspectObserver$1$b2b6354()
  17. {
  18. System.out.println("[AspectObserver] speaker is about to speak!");
  19. }
  20. public void ajc$afterReturning$test_aspectj_AspectObserver$2$b2b6354()
  21. {
  22. System.out.println("[AspectObserver] speaker has completed his speech!");
  23. }
  24. public static AspectObserver aspectOf()
  25. {
  26. if(ajc$perSingletonInstance == null)
  27. throw new NoAspectBoundException("test_aspectj_AspectObserver", ajc$initFailureCause);
  28. else
  29. return ajc$perSingletonInstance;
  30. }
  31. public static boolean hasAspect()
  32. {
  33. return ajc$perSingletonInstance != null;
  34. }
  35. private static void ajc$postClinit()
  36. {
  37. ajc$perSingletonInstance = new AspectObserver();
  38. }
  39. private static Throwable ajc$initFailureCause;
  40. public static final AspectObserver ajc$perSingletonInstance;
  41. static
  42. {
  43. try
  44. {
  45. ajc$postClinit();
  46. }
  47. catch(Throwable throwable)
  48. {
  49. ajc$initFailureCause = throwable;
  50. }
  51. }
  52. }

3、运行一下Speaker.class

得到结果:

  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函数中,方法被调用的前后

  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代码差不了多少。

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

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

同样,可知

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

是怎么一回事啦。

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

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

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

AspectJ本质剖析的更多相关文章

  1. java8学习之内部迭代与外部迭代本质剖析及流本源分析

    关于Stream在Java8中是占非常主要的地位的,所以这次对它进行进一步探讨[这次基本上都是偏理论的东东,但是理解它很重要~],其实流跟咱们数据库学习当中的sql语句的特点是非常非常之像的,为什么这 ...

  2. 【转】self.myOutlet=nil、viewDidUnload、dealloc的本质剖析

    对于iphone开发人员来说,内存管理是极为重要的技巧,哪怕程序的功能再强大,设计再漂亮,如果内存控制不好,也难逃程序莫名退出的噩运,这与网页开发是完全不同的. 内存控制里面有很多门道,在这里分析一下 ...

  3. C++中的引用

    一,C++中引用的基础知识 1.引用的基本概念 1.所谓的引用其实就是对变量起“别名”.引用和变量对应得是相同的内存,修改引用的值,变量的值也会改变,和指针类似. 2.引用在定义的时候必须要初始化,初 ...

  4. LINQ的高级应用

    ---恢复内容开始--- 本文不想罗列linq的通俗使用方法.因为很多博文都已经写得很详细了. 此处直接贴出源码,如果有需要的朋友可以参考,希望更多的朋友能够补充更多的linq的高级应用. 源码如下: ...

  5. C++ 学习路线和看法

    C++ 学习路线和看法 原文地址:http://shundacao.blog.163.com/blog/static/1340404812010101982751101/     C++大体分为C++ ...

  6. MySQL数据库事务各隔离级别加锁情况--read uncommitted篇(转)

    本文转自https://m.imooc.com/article/details?article_id=17291,感谢作者 1.目的 1.1 合适人群 1.数据库事务特征我只是背过,并没有很深刻的理解 ...

  7. C++封装随笔

    1接口的封装和设计思想入门 接口的封装和设计思想入门 第一套api函数 #ifndef _CLT_SOCKET_H__ #define _CLT_SOCKET_H__ //客户端初始化环境 int c ...

  8. Paper | Predicting the Quality of Images Compressed After Distortion in Two Steps

    目录 1. 问题本质剖析 2. 方法细节 图像质量评估大佬AC Bovik的论文,发表在2019 TIP上. 考虑的问题:对于有参考图像质量评估(R-IQA)任务,参考图像有时是有损的.这会导致评估的 ...

  9. SpringAOP ApectJ 动态代理

    参考链接:https://docs.spring.io/spring/docs/4.3.13.RELEASE/spring-framework-reference/htmlsingle/#aop ht ...

随机推荐

  1. BZOJ4010: [HNOI2015]菜肴制作

    Description 知名美食家小 A被邀请至ATM 大酒店,为其品评菜肴. ATM 酒店为小 A 准备了 N 道菜肴,酒店按照为菜肴预估的质量从高到低给予 1到N的顺序编号,预估质量最高的菜肴编号 ...

  2. new在c#方法中的使用

    new在c#中有三种用法: 1.实例化对象 2.泛型约束 3.用在方法前.new和override的区别在于:override用于重写父类的方法:new用于隐藏方法,它调用的方法来自于申明的类,如果申 ...

  3. v.size() return size_t not int 返回无符号整型数

    In the C++ STL, the vector size() function return size_t, which is unsigned int, not int. So imagine ...

  4. Win2K3一句话开3389

    网上流传了很多开3389的exe小工具,还有读写注册表的bat批处理,有的是操作注册表,有的是操作各种组件这里提供一个不会被拦截,而且可以使用的开3389的cmd一句话: wmic RDTOGGLE  ...

  5. Codeforces Round #375 (Div. 2)——D. Lakes in Berland(DFS连通块)

    D. Lakes in Berland time limit per test 2 seconds memory limit per test 256 megabytes input standard ...

  6. 一看就懂的Android APP开发入门教程

    一看就懂的Android APP开发入门教程 作者: 字体:[增加 减小] 类型:转载   这篇文章主要介绍了Android APP开发入门教程,从SDK下载.开发环境搭建.代码编写.APP打包等步骤 ...

  7. Unity中的协程(一)

    这篇文章很不错的问题,推荐阅读英文原版: Introduction to Coroutines Scripting with Coroutines   这篇文章转自:http://blog.csdn. ...

  8. /etc/hosts.conf

    一 作用       指定如何解析主机域名.可设置网络安全. 二 参数说明      默认情况,/etc/hosts.conf 文件有如下内容——      order hosts,bind     ...

  9. Introducing the Accelerated Mobile Pages Project, for a faster, open mobile web

    https://googleblog.blogspot.com/2015/10/introducing-accelerated-mobile-pages.html October 7, 2015 Sm ...

  10. Types of compression algorithms

    http://www.html5rocks.com/en/tutorials/speed/img-compression/ Types of compression algorithms There ...