首页 > 代码库 > AOP技术研究--AOP概述

AOP技术研究--AOP概述

1 前言


1.1 软件编程技术发展


软件编程技术与程序设计语言是分不开的。过去的几十年中,程序设计语言对抽象机制的支持程度不断提高:从机器语言到汇编语言,到高级语言,再到面向对象语言。每一种新的程序设计语言的出现都带来软件编程方法的飞跃。汇编语言出现后,开发人员避免了直接使用0-l编码,而是利用符号来表示机器指令,从而更方便地编写程序。当程序规模继续增大的时候,出现了以Fortran、C、Pascal等为代表的高级语言,这些高级语言使得编写复杂的程序变得容易,开发人员可以更好地应付日益复杂的代码,这一阶段的软件开发方法被称为“面向过程的”。但是,随着软件产业的迸一步发展,更大、更复杂的软件系统在需求中被提出,即使开发人员应用结构化程序设计的方法,仍然很难把握软件开发的整体局势。在这种情况下,作为降低开发复杂性的工具,诸如C++、Java等面向对象的语言产生了,面向对象程序设计也随之发展起来,软件编程方法学也由“面向过程”过渡到“面向对象(OOP)”时代。不难发现,编程技术与编程语言定义了人与机器之间的通信方式[1]。每一种新的技术都提供了一些新的方法来解决之前所未能很好解决的问题。例如,通过独立于机器的代码将晦涩难懂的0-1指令抽象出来:通过面向过程的编程语言使人们可以采用结构化的设计方式来构造较为复杂的系统;通过面向对象编程语言中的类来封装具体数据和方法的实现细节使人们将复杂的系统进行详细的划分等。每一种新的技术都提供了一种更为自然的方式来将系统需求映射为编程结构。编程技术的不断发展可以使人们创建复杂度更高的系统,反之亦然,人们允许复杂度越来越高的系统存在,因为新的技术可以用来处理这种复杂性。


1.2 OOP

1.2.1 OOP的概念


OOP:Object-Oriented programming(面向对象程序设计)是一种程序设计范型,同时也是一种程序开发的技术。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和可扩展性。
OOP是一种运用对象,类,继承,聚合,消息传递,多态性来构造软件开发的方法,在系统构造中尽可能运用人类的自然思维方式。其主要的概念[2]如下:
(1) 对象(object):是系统中用来描述客观事物的一个实体,它是构成系统的一个基本单位,一个对象由一组属性和对这组属性进行操作的一组服务构成。
(2) 类(class):具有相同属性和服务的一组对象的集合,它为属于该类的全部对象提供了统一的抽象描述,其内部包括属性和服务两个部分。
(3) 封装(encapsulation):把对象的属性和服务结合成一个独立的系统单位,并尽可能隐蔽对象的内部细节。
(4) 继承(inheritance):特殊类的对象拥有其一般类的全部属性和服务,称作特殊类对一般类的继承。
(5) 多态(polymorphism):指一般类中定义的属性或服务被特殊类继承之后,可以具体不同的数据类型或表现出不同的行为。

OOP可以看作一种在程序中包含各种独立而又互相调用的对象的思想,这与传统的思想刚好相反:传统的程序设计主张将程序看作一系列函数的集合,或者直接就是一系列对电脑下达的指令。面向对象程序设计中的每一个对象都应该能够接受数据、处理数据并将数据传达给其它对象,因此它们都可以被看作一个小型的“机器”,即对象。

1.2.2 OOP的优点

OOP技术出现以前,结构化设计是程序设计的主流。结构化程序设计又称为面向过程的编程方式。在面向过程的编程方式中,需求被看作一系列需要完成的任务,函数用于完成这些任务,解决问题的焦点集中于函数。其中函数是面向过程的,即它关注如何根据规定的条件完成指定的任务。在多函数程序中,许多重要的数据被放置在全局数据区,这样它们可以被所有的函数访问,同时每个函数都可以具有自己的局部数据。图1.1显示了面向过程编程中函数与数据之间的关系。


图1.1 面向过程编程中函数与数据之间的关系[3]

这种结构很容易造成全局数据无意中被其他函数改动,因此程序的正确性不易保证。面向对象编程的出发点之一就是弥补面向过程编程的这一缺点。在面向对象编程中,对象是程序的基本元素,它将数据和操作紧密地连结在一起,并保护数据不会被外界的函数意外地改变。图1.2显示了面向对象程序设计中对象、数据和方法之间的关系。


图1.2 面向对象程序设计中对象、数据和方法之间的关系[3]
比较OOP和面向过程编程,还可以得到面向对象编程的其他优点[4]:
(1) 数据抽象的概念可以在保持外部接口不变的情况下改变内部实现,从而减少甚至避免对外界的干扰。
(2) 通过继承机制不仅可大幅减少冗余的代码,而且还可以方便地扩展现有代码,从而提高了编码效率,减少了编码出错概率,降低软件维护的难度。
(3) 结合面向对象的分析、设计,允许将问题域中的对象直接映射到程序中,减少软件开发过程中中间环节的转换过程。
(4) 通过对对象的辨别、划分,可以将软件系统分割为若干相对独立的部分,在一定程度上便于控制软件复杂度。
(5) 以对象为中心的设计可以帮助开发人员从静态属性和动态方法两个方面把握问题,从而更好地实现系统。
(6) 通过对象的聚合、联合,可以在保证封装与抽象的原则下实现对象内在结构和外在功能上的扩充,从而实现对象功能由低级到高级的转变。

1.2.2 OOP的缺点

面向对象的编程方法在软件开发领域引起了重大变革,极大地提高了软件开发的生产率,为解决软件危机带来了光明。但是,和其他编程方法一样,面向对象编程也并非完美无缺。例如,采用面向对象的编程方式能够很好地解决软件系统中角色划分的问题,将软件开发中的许多关注点都模块化,并能够把这些关注点的具体实现细节封装在类中。但是,在系统中还存在另一类关注点,它们并不是某一个模块或者类所特有的,它们可能横跨多个模块或类,例如日志功能就可以被系统中的许多模块引用。面向对象编程在处理此类关注点时所采用的办法就不够理想,从而造成了代码的混乱和分散[5~7]。可以通过一个简单的例子来说明采用向向对象编程实现横切关注点所带来的问题,这里给出一个封装了业务逻辑的类的实现框架:
public class BusinessClass extends BaseBusinessClass {
//核心数据成员
//其他数据成员:日志流,保证数据完整性的标志位等
//重载基类的方法
public void performSomeOperation(OperationInformation info) {
//安全性验证
//检查传入数据是否满足协议
//锁定对象以保证当其他线程访问时的数据完整性
//检查缓存中是否为最新信息
//记录操作开始执行时间
//执行核心操作
//己录操作完成时间
}
// 一些类似操作
public void save(PersitanceStorage ps) {}
}
在上面的代码中,存在两个问题:第一,其它数据成员不是这个类的核心关注点;第二,performSomeOperation()方法的实现做了许多核心操作之外的事,它要处理同志、验证、线程安全、协议验证和缓存管理等一些外围操作,而且这些外围操作同样也会应用于其他类。上述两个问题,归根到底是由于OOP未能将系统中被多个模块所共同享用的需求很好的模块化而引起的。

为了解决横切关注点的模块化实现,一种新的编程技术—AOP面向方面编程(Aspect-Oriented Programming)应运而生。

2 AOP概述
2.1 AOP思想
AOP: Aspect Oriented Programming 面向切面编程。
面向切面编程(也叫面向方面编程):Aspect Oriented Programming(AOP),是目前软件开发中的一个热点。AOP实际上是GoF(Observer Design Pattern)设计模式的延续,强调是调用者和被调用者之间的解耦,未开发者提供了一种描述横切关注点(Crosscutting Concern)的机制,并能够自动将横切关注点织入(weaving)到面向对象的软件系统中,从而实现了横切关注点的模块化,通过划分方面(Aspect)代码,横切关注点变得很容易处理。开发者可以在编译时更改,插入或除去系统的方面,甚至重用系统的切面[2]。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
在我们设计一个新系统时,首先需要关注的是如何处理那些主要的核心功能,对于商业应用来说也就是基本的业务逻辑。例如在一个银行应用系统中,核心模块用来处理储户使用的银行事务:在一个零售应用系统中,核心模块用来处理购买商品业务和库存管理业务。在这两个应用中,还存在一些全系统范围的共同关注点,例如日志记录、用户认证、数据持久性以及其他一些对很多核心业务模块来说共用的要素。这些分布在多个模块中的系统范围特性被称为横切关注点[5,6,7,9,10]。面向方面编程(AOP)就是处理这些横切关注点的。虽然面向对象编程(AOP)是当前处理核心关注点[5]最广泛的方法,但它对于横切关注点的处理还不够理想。典型的OOP所实现的核心关注点和横切关注点之间的耦合是不够理想的,如果要增加新的横切特性或者修改现存的横切功能,就必须对所有相关的核心模块进行修改,使得系统的维护和扩展变的异常困难,而导致这种现象的根本原因在于横切关注点在OOP中的实现方式都是分散在各个核心关注点内部的。
AOP是一种新技术,它的核心思想是将系统中的横切关注点和核心关注点分别模块化,其中横切关注点通过方面(aspect)实现模块化,核心关注点通过类(class)实现模块化,再通过一个类似于编译器的工具——切面编织器(Aspect weaver)[5~7] (也可以称为方面编译器)对已模块化的两类关注点进行编译,从而构造出新的系统。在传统的开发技术中并没有强调横切关注点这个概念,使得客观存在的横切需求被迫实现在核心需求的代码中,从而导致了代码的混乱和分散。因此,如何将横切关注点从核心需求模块中分离出来,成为面向切面技术首要的任务[10]。
2.2 AOP基本概念
在面向对象编程(OOP)中,类,对象,封装,继承,多态等概念是描述面向对象思想主要术语。与此类似,在面向切面编程中,同样存在着一些基本概念。
2.2.1 关注点
关注点(concern):一个关注点可以是一个特定的问题,概念,或者是应用程序域,总而言之,应用程序必须达到的一个目标。关注点分为核心关注点和横切关注点。核心关注是有关业务逻辑,比如生成工资单,让员工记录,做银行转帐。横切关注点的定义见2.2.2横切关注点。
2.2.2 横切关注点
横切关注点(Crosscutting Concerns):是一个关注点(concern)就是一个特定的目的,一块我们感兴趣的区域,从技术的角度来说,一个典型的软件系统可以映射成一些核心关注点和系统关注点。举例子来说,一个信用卡出来的系统的核心关注点是借贷/存入处理,而系统级的关注点则是日志,事务处理,授权,安全及其性能问题等,它们会在多个模块中出现,我们称其为横切关注点。横切关注点会在多个模块中出现。如果使用现有的编程方法,横切关注点会横越多个模块,结果是使系统难以设计、理解、实现和演进。AOP能够比上述方法更好地分离系统关注点,从而提供模块化的横切关注点。
2.2.3 连接点
连接点(joint point):是在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候,关注点将在这里横切应用程序。连接点可以是方法调用、构造函数调用、异常处理程序、或者程序执行中的其他点。联结点是 AOP 的核心概念之一,它用来定义在程序的哪里通过 AOP 加入新的逻辑。在Spring AOP中,一个连接点总是表示一个方法的执行。 
2.2.4 切入点
切入点(Pointcut):一个切入点是用来定义某一个通知该何时执行的一组联结点。通过定义切入点,我们可以精确地控制程序中什么组件接到什么通知。上面我们提到,一个典型的连结点是方法调用,而一个典型的切入点就是对某一个类的所在方法调用的集合。通常我们会通过组建复杂的切入点来控制通知什么时候被执行。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时)。切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法。
2.2.5 通知
通知(advice):通知作为AOP语言的主要程序结构之一, 通常与某个切入点相关联,用来描述在相应连接点处所需调用的程序逻辑,其结构类似于OOP中的方法(method)。实际上,在很多AOP语言中就是把通知作为方法来进行存储和调用的。不同之处主要在于:调用方法时需要将其调用语句显式地写在基础程序中;
而调用通知则体现了AOP中所强调的好莱坞法则(Hollywood princple不需要在基础程序的代码中显式调用通知,其调用逻辑会被织入机制自动插入到基础程序的执行流程中。这种方式使开发人员在编写基础程序时不需要考虑通知的存在,可以更加专注于业务逻辑[14] 。基本通知的种类如下:
前置通知(Before advice):在某连接点之前执行的通知,但这个通知不能阻止连接点之前的执行流程(除非它抛出一个异常)。 
后置通知(After returning advice):在某连接点正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。 
异常通知(After throwing advice):在方法抛出异常退出时执行的通知。 
最终通知(After (finally) advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。 
环绕通知(Around Advice):包围一个连接点的通知,如方法调用。这是最强大的一种通知类型。环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它自己的返回值或抛出异常来结束执行。 
2.2.6 切面
切面(Aspect,也译作方面):一个关注点的模块化,这个关注点可能会横切多个对象,其地位就相当于OOP中的类,它将通知,连接点以及类型间声明的一个组合。同类相似,方面也可以有自己的成员函数和变量,从其他类或者方面扩展以及实现接口等。与类不同的是方面的构造是由AOP框架来构造的,不能像类一样使用new关键字来显式生成实例[11]。
切面从抽象意义上讲,是对系统组件的性能和语法产生一定影响的一些属性[12];从设计上讲,是横切系统的一些软件系统关注点;从实现上讲.切面是一种程序构造单元。它支持将横切系统的关注点封装到单独的模块单位中[13],典型的切面如异常处理,日志处理,安全验证和事务处理等模块。
2.2.7 目标
目标(target):目标是一个被切入的地方,它一般是核心关注点,业务功能。例如2.2.2横切关注点中举例的信用卡系统的核心关注点是借贷/存入处理就是目标。
2.2.8 目标对象
目标对象(Target Object):被一个或者多个切面所通知的对象。也被称做被通知(advised)对象,也即被织入横切关注点的对象,即该对象是切入点选择的对象。它在执行过程中会受到某一个AOP的修改,例如在 Spring AOP是通过运行时代理实现的,这个对象永远是一个被代理(proxied)对象。
2.2.9 编织
编织(Weaving,又译为织入):组装切面创建通知化对象[2]。织入是将切面真正加入程序代码的过程。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其它纯Java AOP框架一样,运行时完成织入。
2.3 横切
横切是AOP的关键技术,也就是AOP的核心。这也是正式AOP和OOP差别之所在,一个系统按照00P的视角可以按照功能“纵向”分割为一个个的对象(如继承)。而AOP则从“横向”的角度将系统的一部分分割为一个个方面。“横切”是AOP的专有名词。它是一种蕴含强大力量的相对简单的设计和编程技术。尤其是用于建立松散耦合的、可扩展的企业系统时。横切可以使得AOP在一个给定的编程模型中穿越既定的职责部分的操作。如果不使用横切技术。软件开发是怎样的情形呢?在传统的程序中,由于横切行为的实现是分散的。开发人员很难对这些行为进行逻辑上的实现或更改。例如.用于日志记录的代码和主要用于其它职责的代码缠绕在一起。根据所解决的问题的复杂程度和作用域的不同。所引起的混乱可大可小。更改一个应用程序的日志记录策略可能涉及数百次编辑——即使可行。这也是个令人头疼的任务[15]。
2.4 关注点识别
在一个复杂的系统中,它由许多关注点组合而成,如业务逻辑、性能,数据存储、日志和调度信息、授权、安全、线程、错误检查等。如图2.1不同模块实现的一批关注点组成一个系统。

图2.1 不同模块实现的一批关注点组成的系统
通过对系统需求和实现的识别,我们可以将模块中的这些关注点分为:核心关注点和横切关注点。对于核心关注点而言,通常来说,实现这些关注点的模块是相互独立的,他们分别完成了系统需要的商业逻辑,这些逻辑与具体的业务需求有关。而对于日志、安全、持久化等关注点而言,他们却是商业逻辑模块所共同需要的,这些逻辑分布于核心关注点的各处。在AOP中,诸如这些模块,都称为横切关注点。应用AOP的横切技术,关键就是要实现对关注点的识别。
如果将整个模块比喻为一个圆柱体,那么关注点识别过程可以用三棱镜法则来形容,穿越三棱镜的光束(指需求),照射到圆柱体各处,获得不同颜色的光束,最后识别出不同的关注点。如图2.2 关注点识别-三菱镜法则

图2.2 关注点识别-三菱镜法则
上图识别出来的关注点中,Business Logic属于核心关注点,它会调用到Security,Logging,Persistence等横切关注点。
2.5 将横切关注点编织到核心关注点中
AOP的目的,就是要将诸如Logging之类的横切关注点从BusinessLogic类中分离出来。利用AOP技术,可以对相关的横切关注点封装,形成单独的切面。这就保证了横切关注点的复用。由于BusinessLogic类中不再包含横切关注点的逻辑代码,为达到调用横切关注点的目的,可以利用横切技术,截取BusinessLogic类中相关方法的消息,例如SomeOperation()方法,然后将这些切面编织到该方法中。将横切关注点编织到核心关注点中,如图2.3 AOP模型

图2.3 AOP模型
通过利用AOP技术,改变了整个系统的设计方式。在分析系统需求之初,利用AOP的思想,分离出核心关注点和横切关注点。在实现了诸如日志、事务管理、权限控制等横切关注点的通用逻辑后,开发人员就可以专注于核心关注点,将精力投入到解决企业的商业逻辑上来。同时,这些封装好了的横切关注点提供的功能,可以最大限度地复用于商业逻辑的各个部分,既不需要开发人员作特殊的编码,也不会因为修改横切关注点的功能而影响具体的业务功能。

[1]  蓝红苑,LAN Hong-yuan.面向方面的编程方法[期刊论文]-电脑知识与技术(学术交流)2007,2(9)
[2]  贺庆和.AOP编程思想的研究-软件导刊2010,9(3)
[3] 魏巍.面向切面编程反法的研究与应用[学位论文]2008
[4]  幸俊.AOP开发过程研究及应用[学位论文]2007
[5]  金望正,李莹,徐江浩,李赣生,Jin Wangzheng,Li Ying,Xu Jianghao,Li Gansheng.面向方面编程技术研究[期刊论文]-计算机应用与软件2005,22(8)
[6]  胡志刚,倪硕,HU Zhi-gang,NI Shuo.面向方面程序设计及其实现技术[期刊论文]-计算机工程与设计2005,26(8)
[7]  郭东亮,张立臣,GUO Dong-liang,ZHANG Li-Chen.面向方面软件开发研究[期刊论文]-计算机应用研究2005,22(8)
[8]  邓阿群,厉小军,俞欢军,胡上序.一种新型软件设计方法AOP的研究[期刊论文]-系统工程与电子技术2004,26(7)
[9]  林云,LIN Yun.基于面向方面编程方法的研究[期刊论文]-电脑知识与技术2010,6(8)
[10] 宋小鹏,盛仲飚,潘宏侠,白晓峰.面向方面编程方法的研究[期刊论文]-微计算机信息2006(12)
[11] 韦振远.基于AOP技术研究与探讨.应用科学.2008(15)
[12] 张瞩熹,王怀民.基于AOP的软件运行轨迹捕获技术研究与实现[期刊论文]-计算机应用 2008(5)
[13] 张瞩熹,郭长国,苑洪亮,王怀民.基于AOP技术的通用线程监控平台的研究与实现[期刊论文]-计算机工程与科学2007(5)
[14] 唐祖锴,彭智勇,TANG Zukai,PENG Zhiyong.面向方面程序设计语言研究综述.计算机科学与探索.2010,4(1)
[15] 吕航飞.AOP编程技术探析.电脑知识和技术(学术交流).2007,4(21)
[16] 黄雷.论AOP和OOP.电脑知识与技术(学术交流).2006,4(20)
[17] 王申源,董传良,刘英丹.面向方面的编程的研究与实现.计算机应用研究2004,21(11)
[18] Ramnivas Laddad I want my AOP!.(Part1~ Part3)
[19] 袁绪峰.基于Spring宽假的AOP编程.计算机与现代化.2006(1)
[20] 唐祖锴,彭智勇,TANG Zukai,PENG Zhiyong.面向方面程序设计语言研究综述.计算机科学与探索2010,4(1)
[21] 王雪松,陈瞻,唐雪飞.AOP及其编织技术的研究.福建电脑.2006(3)

AOP技术研究--AOP概述