http://book.51cto.com/art/200811/97334.htm
对于AOP编程而言,程序的主要逻辑部分和Aspect功能部分的具体实现都可以采用传统的OO技术等实现,这里没有什么新东西。AOP最为特别并使其相对其他方法具有明显优点的部分就在于,它能够以多样的方式将程序中用到的多个方面灵活地织入(Weave)到一起,形成一个完整的应用程序。因而在学习AOP编程时,如何以准确、简洁、灵活的方式将各个不同的方面织入到一起,就成为了我们最需要注意的关键点。
大致上,织入操作可以发生在如下几个阶段。
编译时:在对源代码进行编译时,特殊的编译器允许我们通过某种方式指定程序中的各个方面进行Weave的规则,并根据这些规则生成编译完成的应用程序;
编译后:根据Weave规则对已经完成编译的程序模块进行Weave操作;
载入时:在载入程序模块的时候进行Weave操作;
运行时:在程序运行时,根据情况织入程序中的对象和方面。
在表2-1中列出了目前几种主流的AOP系统所支持的织入操作时机。
表2-1 AOP支持Weave时机列表
织入时机 | AspectJ | Spring | JBoss | AspectC |
编译时 | √ |
|
| √ |
编译后 | √ |
|
| √ |
加载时 | √ | √ | √ |
|
运行时 |
|
| √ |
|
选择合适的织入时机对于AOP应用来说是非常关键的。针对具体的应用场合,我们需要作出不同的抉择。可以看到,AspectJ为我们提供了最多的选择,即使没有直接支持的运行时Weave,也可以通过一个简单的模式来实现。在使用Spring或JBoss提供的AOP框架时,我们可以利用AspectJ来补足这两个框架的不足之处,从而获得更为灵活的织入策略。
下面来分析不同的织入时机的优缺点。
1.编译时Weave
编译时织入,即在编译Java源代码时,将Aspect源代码织入到Class代码中,如图2-2所示。
(点击查看大图)图2-2 编译时织入 |
对于普通应用程序而言,在编译时进行Weave操作是最为直观的做法。由于在源程序中包含了应用的所有信息,因此这种方式通常支持最多种类的联结点。利用编译时Weave,我们能够使用AOP系统进行细粒度的Weave操作,例如读取或写入字段。在源代码编译之后形成的模块将丧失大量的信息,因此通常采用粗粒度的AOP方法。同时,对于传统的编译成为本地代码的语言如C++、Fortran等来说,编译完成后的模块往往跟操作系统平台相关,这就给建立统一的编译后、载入时及运行时Weave机制造成了困难。对于编译成为本地代码的语言而言,只有在编译时进行Weave才最为可行。
尽管编译时Weave具有功能强大、适应面广泛等优点,但它的缺点也很明显。首先,它需要程序员提供所有的源代码,因此对于模块化的项目就有点力不从心了。即使能够提供所有模块的源代码,它也造成了程序不能进行增量编译、编译时间变慢等不利之处。
2.编译后Weave
编译后织入,即是将Aspect的源代码,织入到编译后的Class二进制代码中,以形成新的Class代码,如图2-3所示。
(点击查看大图)图2-3 编译后织入 |
为了解决模块化编程的要求,有些AOP框架开始支持编译后Weave的功能。程序员只需要获得编译完成之后的模块,就能进行Weave操作。在AspectJ中,不管是程序的主逻辑部分还是方面,都可以在先编译成为模块之后进行Weave,而且主逻辑部分完全可以采用普通的JavaC编译。而在AspectC中,进行编译后Weave的要求是所有的程序模块都采用AspectC进行编译。可以看出,使用Java这样基于虚拟机的语言对于编写AOP程序是有优势的。
3.加载时Weave
尽管编译后Weave已经解决了在不能获得所有源代码时进行AOP编程的需要的问题,但是在这个框架流行的时代,我们需要更为灵活地安排我们的Weave操作。如果程序的主逻辑部分和Aspect作为不同的组件开发,那么最为合理的Weave时机就是在框架载入Aspect代码之时。如果在进行载入时Weave,则Weave操作之后的结果将不会被保存。程序的主逻辑部分和Aspect部分可以分别进行开发和编译,而Weave操作则在程序载入时发生。
AspectJ、Spring和JBoss都支持载入时Weave。在Spring和JBoss的AOP实现中,框架先于应用程序启动,由框架来负责Weave操作的进行。而在AspectJ中,一个特殊的类加载器被用于这个目的。这个类加载器可以方便地嵌入到框架应用程序中,从而能够为任意的框架提供AOP支持。
4.运行时Weave
运行时Weave可能是所有Weave方式中最为灵活的,程序在运行过程中可以为单个的对象指定是否需要Weave特定的Aspect。在JBoss项目中,利用运行时Weave的特性完成了JBoss Cache项目。在JBoss Cache中,如果一个对象被放置到Cache中,它的状态就将被CacheAOP监视,并且它的状态会被自动同步到一个分布式的缓存中。如果这个对象不需要被缓存,那么它就和AOP不发生任何关系,对它的修改不会引发Cache的同步操作。值得一提的是,尽管AspectJ没有明确提供运行时Weave的能力,但在AspectJ中可以通过一个简单的Pattern实现来运行时Weave。