AOP:选择正确的时机进行编织

在本文中,我们将采用三种重要的实现的例子,来实践本文提出的概念。这三种 AOP 实现是 AspectJ,Spring 和 JBoss。通过比较他们在 Weave 时机方面的不同,来获得对于如何选择 Weave 时机进行判定的准则。由于 AspectWerk 已经合并到 AspectJ 中,我们将不再对其进行单独的评论。

对于 AOP 编程而言,程序的主要逻辑部分和 Aspect 功能部分的具体实现都可以采用传统的 OO 技术等实现,这里没有什么新东西。AOP 最为特别并使其相对其它方法具有明显优点的部分就在于它能够以多样的方式将程序中用到的多个方面灵活的 Weave 到一起,形成一个完整的应用程序。因而在学习 AOP 编程时,如何以准确、简洁、灵活的方式将各个不同的方面 Weave 到一起,就成为了我们最需要注意的关键点。接下来,我们将阐述 Weave 操作发生的不同时机,并介绍其适用的场合。

大致上,Weave 操作可以发生在如下几个阶段:

  • 编译时:在对源代码进行编译时,特殊的编译器允许我们通过某种方式指定程序中各个方面进行 Weave 的规则,并根据这些规则生成编译完成的应用程序。
  • 编译后:根据 Weave 规则对已经完成编译的程序模块进行 Weave 操作。
  • 载入时:在载入程序模块的时候进行 Weave 操作
  • 运行时:在程序运行时,根据程序运行时的情况 Weave 程序中的对象和方面

在表 1 中列出了目前几种主流的 AOP 系统所支持的 Weave 操作时机。

编译时 Weave

对于普通应用程序而言,在编译时进行 Weave 操作是最为直观的做法。由于源程序中包含了应用的所有信息,因此这种方式通常支持最多种类的联结点。利用编译时 Weave,我们能够使用 AOP 系统进行细粒度的 Weave 操作,例如读取获写入字段。源代码编译之后形成的模块将丧失大量的信息,因此通常采用粗粒度的 AOP 方法。同时,对于传统的编译成为本地代码的语言如 C++、Fortran 等来说,编译完成后的模块往往跟操作系统平台相关,这就给建立统一的编译后、载入时以及运行时 Weave 机制造成了困难。对于编译成为本地代码的语言而言,只有在编译时进行 Weave 最为可行。尽管编译时 Weave 具有功能强大、适应面广泛等优点,但他的缺点也很明显。首先,它需要程序员提供所有的源代码,因此对于模块化的项目就力不从心了。即使能够提供所有模块的源代码,它也造成了程序不能进行增量编译、编译时间变慢等不利之处。

后编译时 Weave

为了解决模块化编程的要求,有些 AOP 框架开始支持后编译时 Weave 的功能。程序员只需要获得编译完成之后的模块,就能进行 Weave 操作。在 AspectJ 中,不管是程序的主逻辑部分还是方面都可以先编译成为模块之后进行 Weave,而且主逻辑部分完全可以采用普通的 JavaC 编译。而在 AspectC 中,进行后编译时 Weave 的要求是所有的程序模块都采用 AspectC 进行编译。可以看出,使用 Java 这样基于虚拟机的语言对于编写 AOP 程序是有优势的。

载入时 Weave

尽管后编译时 Weave 已经解决了不能获得所有源代码时进行 AOP 编程的需要,但是在这个框架流行的时代,我们需要更为灵活的安排我们的 Weave 操作。如果程序的主逻辑部分和 Aspect 作为不同的组件开发,那么最为合理的 Weave 时机就是在框架载入 Aspect 代码之时。因此我们可以看到,在 JBOSS 和 Spring 中都提供了这样的方式进行 Weave 操作。在进行载入时 Weave 时,Weave 操作之后的结果不会被保存。程序的主逻辑部分和 Aspect 部分可以分别进行开发和编译,而 Weave 操作在程序别载入时发生。AspectJ、Spring 和 JBoss 都支持载入时 Weave。在 Spring 和 JBoss 的 AOP 实现中,框架先于应用程序启动,由框架来负责 Weave 操作的进行。而在 AspectJ 中,一个特殊的类加载器被用于这个目的。这个类加载器可以方便的嵌入到框架应用程序中,从而能够为任意的框架提供 AOP 支持。使用 AspectJ 进行载入时 Weave 需要几个步骤:

1. 在编译时为编译器指定 -Xreweavable 选项来使得 AspectJ 编译器在 .class 文件中保存额外的 Weave 相关信息。

2. 在 .jar 文件中添加 META-INF/aop.xml 来指定 Weave 策略。

3. 在运行时指定 AspectJ 提供的类加载器。对于 jdk 5,我们可以为 java 虚拟机指定 -javaagent 选项。而 JDK 1.4 可以通过系统属性 -Djava.system.class.loader 来指定类加载器。

在下图中给出了一个 AspectJ 中配置运行时 Weave 的配置文件 aop.xml,我们在图中给出了详细的注释,感兴趣的读者朋友可以很容易的了解这段代码的用途:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

1:<aspectj>

2:    <aspects>

3:        <!-- 声明两个将要使用的 Aspects -->

4:        <aspect name="com.MyAspect"/>

5:        <aspect name="com.MyAspect.Inner"/>

6:

7:        <!-- 在配置文件中定义一个 Aspect -->

8:        <concrete-aspect name="com.xyz.tracing.MyTracing"

              extends="tracing.AbstractTracing">

9:         <pointcut name="tracingScope" expression="within(org.maw.*)"/>

10:        </concrete-aspect>

11:             

12:        <!-- 使用任何匹配"com..*"的 Aspect 进行 Weave-->

13:        <include within="com..*"/>

14:             

15:        <!-- 不使用任何具有 @CoolAspect 注解的 Aspect 进行 Weave -->

16:        <exclude within="@CoolAspect *"/>

17:

18:    </aspects>

19:

20:    <weaver options="-verbose -XlazyTjp">

21:    <!-- 对 javax.* 包和 org.aspectj.* 包中的内容进行 Weave 操作。并对 foo 包中

22:    所有不具有 @NoWeave 注解的类型进行 Weave 操作。-->

23:        <include within="javax.*"/>

24:        <include within="org.aspectj.*"/>

25:        <include within="([email protected] foo.*) AND foo.*"/>

26:    </weaver>

27:</aspectj>

28:

在载入时进行 Weave 的过程中,AspectJ 有一些必须遵守的限制:

1. 要求所有将要被 Weave 的代码通过 AspectJ 提供的类加载器载入。

2. Aspect 代码必须对 Weave 类加载器可见,也就是说 Aspect 必须由 Weave 类加载器自身或其父加载器载入。

3. 在 Weave 操作发生之前,所有的 Aspect 代码都已经被载入

运行时 Weave

运行时 Weave 可能是所有 Weave 方式中最为灵活的,程序在运行过程中可以为单个的对象指定是否需要 Weave 特定的 Aspect。在 JBoss 项目中,利用运行时 Weave 的特性完成了 JBoss Cache 项目。在 JBoss Cache 中,如果一个对象被放置到 Cache 中,它的状态就将被 CacheAOP 监视并且它的状态会被自动同步到一个分布式的缓存中。如果这个对象不需要被缓存,那么它就和 AOP 不发生任何关系。对它的修改不会引发 Cache 的同步操作。 值得一提的是,尽管 AspectJ 没有明确提供运行时 Weave 的能力,在 AspectJ 中可以通过一个简单的 pattern 实现运行时 Weave。具体请参见 Adrian 的 Blog:http://www.aspectprogrammer.org/blogs/adrian/2005/03/perinstance_asp.html

小结

选择合适的 Weave 时机对于 AOP 应用来说是非常关键的。针对具体的应用场合,我们需要作出不同的抉择。可以看到,AspectJ 为我们提供了最多的选择,即时没有直接支持的运行时 Weave 也可以通过一个简单的模式来实现。在使用 Spring 或 JBoss 提供的 AOP 框架时,我们可以利用 AspectJ 来补足这两个框架的不足之处,从而获得更为灵活的 Weave 策略。

参考资料

  1. 本文中的例子和讨论基于以下 AOP 实现:

  2. Ramnivas Laddad 撰写的 AspectJ in Action(Manning,2003 年)是一本非常好的关于 AspectJ 的书籍。
  3. Adrian 的 Blog是一个深入了解 AOP 以及 AspectJ 的好地方。
  4. developerWorks Java 技术专区:这里有数百篇关于 Java 编程各个方面的文章。
  5. 加入 developerWorks 中文社区。查看开发人员推动的博客、论坛、组和维基,并与其他 developerWorks 用户交流。

https://www.ibm.com/developerworks/cn/java/j-aop-weave/index.html

原文地址:https://www.cnblogs.com/feng9exe/p/10366596.html

时间: 2024-08-30 14:30:22

AOP:选择正确的时机进行编织的相关文章

[转]oracle设计数据库应选择正确的数据类型

原文地址:http://blog.sina.com.cn/s/blog_5014663501007n40.html 在设计数据库的时候,选择正确的数据类型,往往可以避免很多的问题,正确理解数据库的类型,对于存储空间规划,应用性能调整都会很有帮助,下面是我个人的一点总结: 1. Char 定长格式字符串,在数据库中存储时不足位数填补空格,不建议使用,会带来不必要的麻烦 a.  字符串比较的时候,如果不注意(char不足位补空格)会带来错误 b.  字符串比较的时候,如果用trim函数,这样该字段上

如何选择正确值的上拉电阻和下拉电阻?

如何选择正确值的上拉电阻和下拉电阻?上拉电阻和下拉电阻是如何确定?还是在选择此类电阻的时候,有个特定的范围? 对上拉电阻和下拉电阻的选择应结合开关管特性和下级电路的输入特性进行设定,主要需要考虑以下几个因素: 1. 驱动能力与功耗的平衡.以上拉电阻为例,一般地说,上拉电阻越小,驱动能力越强,但功耗越大,设计是应注意两者之间的均衡.2. 下级电路的驱动需求.同样以上拉电阻为例,当输出高电平时,开关管断开,上拉电阻应适当选择以能够向下级电路提供足够的电流.3. 高低电平的设定.不同电路的高低电平的门

翻译:程序员数据结构基础:选择正确的数据结构

本文转载自GameDev.net,仅供学习交流.因为刚刚开始学习翻译,难免有些疏漏,如果有哪些地方翻译的不正确,请不吝告知,万分感谢. 原文链接:http://www.gamedev.net/page/resources/_/technical/general-programming/data-structures-for-pre-college-programmers-choosing-the-right-structure-r2991 网络上的许多初学者还是学生.通常初学者通过在网上看教程,

(转)权威支持: 选择正确的 WebSphere 诊断工具

权威支持: 选择正确的 WebSphere 诊断工具 原文:https://www.ibm.com/developerworks/cn/websphere/techjournal/0807_supauth/0807_supauth.html 本文提供一个快速参考指南,以帮助您决定要在任何给定时间使用的最常见 WebSphere? 诊断工具,同时还提供了一些背景信息,这些信息提供了有关如何开发问题确定工具的初步认识. 本文来自于IBM WebSphere Developer Technical J

选择正确的自动化测试工具

? Viktor Grebenyuk是一名质量保证专家和测试经理,在测试复杂的(主要是金融领域的)系统和应用程序方面有八年以上的经验.他丰富的经验让他可以:比较不同的测试工具和方法,突出它们的优缺点,并努力找到最适合每个特定案例的正确方法. ? ? ? 测试自动化最近很流行,因为它可以帮助减少测试成本并使某些不能手工执行的测试运行成为可能.自动化测试工具(包括开源工具)的数目也在飞速增长,所以选出最适合每个项目需求的工具还是很不易的.一名测试员该如何选出正确的测试自动化工具呢? 测试自动化工具现

面向目标 vs. 面向功能: 选择正确的Product Roadmap

编者注:本文来自romanpichler,中文版由天地会珠海分舵翻译.主要描述了我们作为产品经理编写我们的Product Roadmap的时候,我们应该如何选择我们Roadmap的类型,应该是面向功能呢,还是面向目标- 面向功能 vs 面向目标 众所周知,Product Roadmap这玩意儿的格式不一而足,且可大可小.而当前最流行的两个格式应该要数"面向功能"和"面向目标"的这两种Product Roadmap了. 前者是是基于产品的功能点的,比如注册功能,搜索功

逸管家:把握不同行业生命周期,选择正确商业模式

</P><P> 原标题:把握不同行业生命周期,选择正确商业模式</P><P> 现今中小企业已进入理性商业模式选择期,大量中小企业在拿到天使投资后进入融资瓶颈期.与此同时,"共享"一词在各地出现,但缺少创业项目运营服务管理能力,能提供的仅仅是基本的公司注册管理和场地服务,无法解决中小企业的软服务提供问题.然而,对于中小企业来说,真正要走向成功必须考虑好三个问题:</P><P> 第一.选择什么样的商业模式;</P

我们如何选择正确的软件进行CAD图纸格式的转换呢?

其实关于CAD图纸格式转换,软件有很多,方法也有很多,CAD是个比较特殊的图纸格式,在建筑.机械.服装行业也广泛的被运用,CAD图纸转换格式也是常常会用到的,那怎么选择正确的软件进行CAD图纸格式的转换呢?CAD图纸格式转换刚发也有很多,可是免费的软件,方便的却不多,xunjieCAD转换器,可以适应各种dwg.dxf.dwf.jpg.png等格式的相互转换.重要的免费软件,还不需要图纸的内存限制.第一步:百度搜索xunjieCAD转换器,直接进入网页点击下载即可. 第二步:安装好之后,在桌面上

选择正确的被重载的方法

今天杭城下雨了本来打算出去找房子的房子到期了,出去找了一圈发现不好找了,时间过得好快,又是一年毕业季啊...回来没事准备写一篇随笔吧. 在面向对象的思想中我们经常会用到方法的重载,但是我们很少去思考编译器是怎样根据方法的签名去决定选择哪个方法的.一般来说发生重载具体用哪个方法是显而易见的,因为只有它的参数数量是正确的所有的实参才能转换成对应的参数类型.但是假如有多个方法看起来都合适就比较麻烦了,这样的情况下就要看每个实参类型转换成参数类型的方式. 举个简单的例子,在同一个Person类中声明了两