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 。
- AspectJ是一个代码生成工具(Code Generator)。
- AspectJ语法就是用来定义代码生成规则的语法。您如果使用过Java Compiler Compiler (JavaCC),您会发现,两者的代码生成规则的理念惊人相似。
- AspectJ有自己的语法编译工具,编译的结果是Java Class文件,运行的时候,classpath需要包含AspectJ的一个jar文件(Runtime lib)。
- ....
看了上面几点,我就想看看它怎么把代码生成了。现在做一个试验。
一个类(包括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.java
- 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();
是怎么一回事啦。
这正是应了上面所提的两点:
- AspectJ是一个代码生成工具(Code Generator)。
- AspectJ语法就是用来定义代码生成规则的语法。
用这两点去感受apectj在程序里该如何去运用使用,就清晰多啦!
AspectJ本质剖析的更多相关文章
- java8学习之内部迭代与外部迭代本质剖析及流本源分析
关于Stream在Java8中是占非常主要的地位的,所以这次对它进行进一步探讨[这次基本上都是偏理论的东东,但是理解它很重要~],其实流跟咱们数据库学习当中的sql语句的特点是非常非常之像的,为什么这 ...
- 【转】self.myOutlet=nil、viewDidUnload、dealloc的本质剖析
对于iphone开发人员来说,内存管理是极为重要的技巧,哪怕程序的功能再强大,设计再漂亮,如果内存控制不好,也难逃程序莫名退出的噩运,这与网页开发是完全不同的. 内存控制里面有很多门道,在这里分析一下 ...
- C++中的引用
一,C++中引用的基础知识 1.引用的基本概念 1.所谓的引用其实就是对变量起“别名”.引用和变量对应得是相同的内存,修改引用的值,变量的值也会改变,和指针类似. 2.引用在定义的时候必须要初始化,初 ...
- LINQ的高级应用
---恢复内容开始--- 本文不想罗列linq的通俗使用方法.因为很多博文都已经写得很详细了. 此处直接贴出源码,如果有需要的朋友可以参考,希望更多的朋友能够补充更多的linq的高级应用. 源码如下: ...
- C++ 学习路线和看法
C++ 学习路线和看法 原文地址:http://shundacao.blog.163.com/blog/static/1340404812010101982751101/ C++大体分为C++ ...
- MySQL数据库事务各隔离级别加锁情况--read uncommitted篇(转)
本文转自https://m.imooc.com/article/details?article_id=17291,感谢作者 1.目的 1.1 合适人群 1.数据库事务特征我只是背过,并没有很深刻的理解 ...
- C++封装随笔
1接口的封装和设计思想入门 接口的封装和设计思想入门 第一套api函数 #ifndef _CLT_SOCKET_H__ #define _CLT_SOCKET_H__ //客户端初始化环境 int c ...
- Paper | Predicting the Quality of Images Compressed After Distortion in Two Steps
目录 1. 问题本质剖析 2. 方法细节 图像质量评估大佬AC Bovik的论文,发表在2019 TIP上. 考虑的问题:对于有参考图像质量评估(R-IQA)任务,参考图像有时是有损的.这会导致评估的 ...
- SpringAOP ApectJ 动态代理
参考链接:https://docs.spring.io/spring/docs/4.3.13.RELEASE/spring-framework-reference/htmlsingle/#aop ht ...
随机推荐
- POJ 1691 Painting A Board(迭代深搜)
题目链接 调了一上午,单步的效率太低了,特别是在有递归的情况下...下午来了,输出调试了下,就发现bug了,各种混乱啊. 比较高兴的事,1Y了.本来还准备用edge1优化一下的,结果完全没用到.. # ...
- CentOS目录结构超详细版
最近初学Linux 对linux的目录产生了很多疑问,看到这篇文章,让我顿时对目录有了一个清晰的认识!推荐给大家! ------------------------------------------ ...
- C# int转byte[],byte[]转int
第一种方法: byte数组转int u = (uint)(b[0] | b[1] << 8 |b[2] << 16 | b[3] << 24); int转byte数 ...
- <META http-equiv=X-UA-Compatible content=IE=EmulateIE7>
未来兼容性中的 META 标记和锁定 注意:本文档是预备文档,随时可能变更. 对于 Web 开发人员来说,文本兼容性是一个要考虑的重要问题.Windows Internet Explorer 8 引入 ...
- 六、saltstack的module组件
Module是saltstack日常使用中用的最多的一个组件.用于管理操作对象. 查看系统module: [root@super65 ~]# salt 'super66' sys.list_modul ...
- openstack是什么
下面图片多来自互联网. 云计算: 云计算层次机构模型: IaaS 基础设施服务 PaaS 平台级服务 SaaS 软件级服务 官网:http://www.openstack.org/ openstack ...
- php读取3389脚本
<?php $regkey = 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\Wds\rdpwd\Td ...
- 初学者对Spring MVC的认识
首先是要一定说明的是,这倒是说明是什么?对吧Spring MVC 是SpringFrameWork的后续产品,并且已经融入到Spring Web Flow中同时Spring MVC 分离了控制器,模型 ...
- svchost.exe是什么?为什么一直在运行
原文:http://www.howtogeek.com/howto/windows-vista/what-is-svchostexe-and-why-is-it-running/ 自己简单翻译了下,图 ...
- hdu1272 并查集
如果要输出yes 需要满足 1 这个图连通 2 没有回路 3 0 0 也是yes 看它有没有回路 在un的时候做一次判断就可以了 然后是判断连通 在这里采用的方法是扫一遍 如果这个点出现过就判断 ...