航海时代

我必须再到海上去,到那孤寂的海天之间……因为潮水奔腾的那种强烈的野性的呼唤,委实教人无法抗拒

导航

<2012年5月>
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

统计

文章分类

档案

随笔分类

相册

.NET牛人榜

常去的站点

开发者园地

我的站点

登录

[编程模式]理解AOP (三)

1、AOP独立于Java

尽管在上一篇的文章里列举了一个AspectJ的例子,但是AOP不是Java特有的一种编程方式。AOP 的概念最早可以追溯到c with class的时代,after,before的设计就是AOP的原型。不过这个特性最终在C++98中被取消,是因为ISO/ANSI标委会认为这个特性的使用频率太低。整个ISO/ANSI的标委会中只有BJ一个人经常使用这个特性。
 
现在回过头来重视AOP,不能不惊叹BJ的在语言设计上的功力,同时也不能不对标委会的短视而感到遗憾。这种缺失甚至影响了现代电脑语言在AOP上的处理能力。没有语言特性的支持,Java的AOP就像是老太太的裹脚布,打开JBOSS的代码,到处能够看到成堆成堆为了实现Interceptor而书写的Reflecting代码。即难看懂又难维护。

用Java实现AOP可以说是不伦不类,原因在于Java语言特性基于静态语言和动态语言之间。即没有C++/C#2.0那样的模板能力,又没有Ruby,Python那样的minxin功能。其实只要在语言特性上做到其中的一点,AOP的解决方案就非常得漂亮。Andrei Alexandrescu的Policy base design的方法其实已经将AOP的特性表现的淋漓尽致。 

template  class Thread 
{
   Lockpolicy lock;
  void Run()
 {
   lock.aquire();
   //do something
   lock.release();
  }   
}
Thread thread1;
Thread thread2;
Thread thread3;

Template的缺点在于需要手工写一点委托代码。但是这些问题都是可以通过工具来解决的。但是从语法上Java根本无法比拟。当然template是一种静态的织入。

Java的采用Relection的AOP与Python,Ruby的mixin相比简直就是小儿科。例如: 

 
class Target1(): 
    def  doSomething1(self): 
        #do Something 

class Target2(): 
    def  doSomething2(self): 
        #do Something 

class AOP: 
    def __init__(self,target): 
        self.target=target 
        self.Interceptor=CreateInterceptorFromConfig() 
    def  __getattr__(self, name): 
         Interceptor.Predo(); 
         self.returnRst=getattr(self.__target, name) 
         Interceptor.Postdo(); 
    def  CreateInterceptorFromConfig(self): 
         #从配置文件中生成interceptor 
if __name__="__main__": 
     AOP  targetAop=Aop(Target1()); 
     targetAop.doSomething1(); 
     AOP  targetAop=Aop(Target2()); 
     targetAop.doSomething2(); 

Python 这类的动态语言天生就是用来做AOP的。Java需要几十行的实现AOP代码,python不超过5行就能解决。 

除了实现上的问题以外,AspectJ还有另外一些问题,一个是AspectJ是不是会过于强大而导致没有用处。为了debug,程序员往往要往代码里加入好多打印语句。当Debug结束后,要是删除这些tracing代码,是个很大的浪费,从测试的角度看,以后万一需要做相同的工作,还要重写。 要是不删除这些代码,效率是个问题,另外,这些代码会模糊正常的business logic代码。 而且,对不同阶段的,不同目标的Debug,你可能希望在不同地方加入不同的Tracing代码,这些代码都留在一块儿,会导致混淆。AOP 所要达到的目标:“把Tracing代码独立出Business Logic代码,通过单独配置的规则动态或静态地编织进目标代码。”。但是,很多Tracing代码是函数进行到中间打印某些变量的值,或者当程序进入到某个分支打印一定的信息。 而AspectJ只能针对函数调用打印信息,这似乎不能解决根本问题。对AspectJ提出的其它例子,我认为用mixin,template是更好的解决方案。AspectJ的方案对于他们来说过于强大了而又显得不必要。
 
第二个是效率问题:由reflecting来实现AOP本来就会消耗大量的资源,这些消耗会有什么影响至今很难说。另外过于统一的织入会让程序损耗不必要的性能,例如Aspect J当中提出一个织入Lock的问题,我们知道lock是非常耗费资源。如果一个方法中我只需要在某一部分织入Lock,但是AOP目前只能做到函数调用上进行织入的话显然会有很多问题。这样武断的织入Lock是我不能认同的。不必要的资源消耗,甚至DeadLock都有可能出现。

2、AOP的分解方法

编译面向方面的程序包括了大量分离的方面表达,以产生通过横切方面描述的通用概念的结果表示,这个编译过程被称为编织(weaving)过程,可能包括合并组件,修改组件,优化等等。编织不一定是一个静态产生过程,可以通过方面程序的运行时解释或者运行时产生来实现,因此Kicales引入术语方面编织(Aspect Weaving)。

我们了解分离Aspect的想法之后,就需要具体的方法和技术,来获得这种分离。主要要解决三个问题:

  1. 什么是需要被分离的重要问题。
  2. 除了调用通用过程,我们还可以使用什么组合机制?
  3. 如何捕捉Aspect?

横切(crosscutting)是方面的核心。

2004年4月20日 15:17

评论

# 回复: [编程模式]理解AOP (三) popcorny

写的太好了
请问还有下一集嘛
我迫不及待了..:P

我想知道有关目前实现AOP有多少方法
就我目前所知
有annotation(attribute)的方式
bytecode manipulationg的方式
interface的方式 jboss4?


2004-4-23 11:26


主题  
姓名  
主页
验证码  
内容   

请不要发表可能给我们带来伤害的政治言论,谢谢配合