免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1068 | 回复: 0
打印 上一主题 下一主题

[翻译]面向方面的java编程 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2005-06-03 23:17 |只看该作者 |倒序浏览
关于AspectJ的断点调试
面向对象编程近年以完全取代面向过程方法成为主流,其最大的优势在于把系统看作是由若干分散的类构造而成,每个类中都良好的定义了相应的任务和责
任。在一个OO应用中,所有的类协作来达到系统的总体目标。然而,系统中的某些部分是无法看做是仅仅某一个类的责任的,这些部分是贯穿(cross-
cutting亦翻译为横切)整个系统而影响很多类,例如:分布式系统的加锁问题、异常处理、日志功能等。当然,处理这些问题的那部分代码可以独立的放在
每个涉及到的类中,但这就违反了如下原则:每个类都要有良好定义的责任。这恰恰是AOP所要解决的问题:AOP定义了一种新的程序结构,被称为方面(为避
免中文表达中"方面"一词的其他含义,文章后面一律使用单词aspect),这个结构被用于把某些横切整个软件系统的部分集中到一些离散的程序实体中。这
样,业务应用类可以保持有良好定义的责任,另外,每个aspect则捕获有横切特性的行为本文分3部分:第1部分解释AOP的概念,第2部分介绍
AspectJ(AOP概念的java语言实现),第3部分比较AOP方法和metalevel(不会翻,元层次??)编程。

AOP基础


们通过一个例子来介绍AOP。设想一个在共享数据上做并发工作的应用,共享的数据可能被封装在一个数据对象中(数据类的一个实例),在这个应用中存在不同
的类的众多对象对一个单一的数据对象做操作,而某一个时刻只能有一个对象能访问数据对象。为有效操作必须引入加锁机制。这意味着每当有对象访问数据对象
时,数据对象必须被锁定(访问结束后解锁)。传统的解决方式为此会引入一个抽象的基类,所有"工作"类都继承它。这个基类定义一个lock()方法和一个
unlock()方法在实际工作完成前后都必须调用这两个方法。
这一方式有如下缺点:
.每个操作数据的方法都要注意锁定,操作代码和锁定相关代码混杂在一起
.单继承的情况下,并非总是可以让所有的工作类全都继承自同一个基类,因为这个单一继承链很可能由于另一个单一继承链的存在而被破坏。在把锁定特性引入已由其他人(比如类库开发人员)设计好的类层次中的时候这个问题是很明显的。
.重用性打了折扣:工作类可能要在其他不需做锁定工作的情况下被重用(或者他们需要使用其他锁定机制)。把实现锁定的代码写在工作类中就把这些类和特定应用中的锁定方式绑定在一起了。

以上例子中的锁定概念有如下特性:
.锁定并非工作类的主要工作
.锁定机制与工作类的主要工作相互独立
.锁定问题横切整.个系统,也就是说,很多类,可能还包括这些类的很多方法都受到锁定
的影响
AOP提供了处理这类问题的另一途径:定义一个新的程序结构来处理横切系统的那部分问题,这个新的结构就是aspect.
在我们的例子中,有一个aspect命名为Lock,它负责如下工作:
.为需要被锁定/解锁的类添加必要的特性以实现锁定/解锁某个对象的工作(在我们的例子中是在数据类Data class中增加lock()方法和unlock()方法)
.确保所有试图修改数据对象Data object的方法在工作之前调用lock()方法及在工作结束后调用unlock()方法(我们的例子中是那些工作类worker classes里的方法)
aspect
还能做些什么呢?举例来说,如果软件系统需要对特定的方法调用(比如用于追踪对象创建的构造器constructor方法)做日志记录,就可以用到
apsect了。这时同样额外需要一个log()方法在代码中的某些地方被调用。当然没人会为了在类层次中引入log()方法而在使用继承关系关联众多完
全不同的类,这时我们可以用AOP的思想来创建一个为有需要的类提供log()方法的aspect,而任何需要到它的地方都可以调用同样这一个方法。第三
个例子是异常处理方面的。可以在一个aspect中为许多类的方法定义若干catch()子句,从而实现整个应用中的统一的异常处理方式。
对于
aspect有两个疑问:1.真的需要aspect吗?当然对于无法用aspect解决某个问题的情况下,aspect就不是必须的。但aspect提供
了新的高层次的抽象从而使设计和理解软件系统变得更容易。当软件规模越来越大时,可理解性就成为一个重大问题了。所以aspect应该会是个有用的工具。
第二个问题可能会是:aspect会不会破坏对象的封装性。有时的确会,但这是可以控制的。aspect要访问与其相关的对象的私有部分,但这至少不会破坏不同的类的对象间的封装性。

AspectJ
AOP
是一种概念,它并不和某个编程语言或编程范例所绑定。他能弥补所有使用单一层级结构(single,hierachical
decomposition)的语言的短处,包括面向过程、面向对象或面向功能的语言。AOP已经被多种语言所实现,比如smalltalk和java。
AOP的java实现被称为AspectJ,是Xerox PARC发明的。
和其他面向aspect的编译器一样,ApsectJ有个编织阶段
(weaving
phase)的工作来明确无误地在类和aspect之间解决横切问题。AspectJ在这个阶段首先使用正[常]规码(regular
code,从词霸查的翻译)编织aspects,然后调用标准的java编译器。

用AspectJ实现示例
接下来描述一下上面那
个锁定的例子的实现。数据类名为Data,他有一些实例变量(有些可能是静态的)和作用在这些实例变量上的方法。有个Worker类来做一些数据上的修改
工作,这些修改可能是时间触发的(time-triggered)。代码段11显示这个类Worker。执行方法的布尔型返回值显示修改是否成功。

代码段1

LISTING 1
-------------------------------------------------------------------------------
01 aspect DataLog {
02      advise * Worker.performActionA(..), * Worker.performActionB(..) {
03          static after {
04              if ( thisResult == true )
05                System.out.println( "Executed "+thisMethodName+
06                "successfully!" );
07              else
08                System.out.println( "Error Executing "+
09                thisMethodName );
10          }
11      }
12 }


码段1定义了一个名为DataLog的aspect,它包含一个所谓的advise 横切面(so-called advise
cross-cut),这个advise影响所有名字和* performAction(..)匹配的方法,
也就是说这些方法必须以performAction开头,可以含有任意参数和任意类型的返回值。这些方法被执行后,这个Datalog的advise
(in the Datalog advice)中 after...那部分代码就会被执行。这样每次调用performActionA() 或
performActionB()
,系统都会打印出该方法是否成功执行的消息。在aspect代码中我们可以使用一些特别的变量,比如包含advise方法执行结果的thisResult
变量,或者是包含当前执行方法的名称的thisMethodName变量。除了after这个advise,还可能有before这样的advise。通
过代码编织器(code weaver),AspectJ能自动把所需的代码引入相应的类中。
下面讨论锁定的例子:当只有一个worker作用于
sharedDataInstance时没什么问题,因为这时锁定不是必须的。设想有一个叫AnotherWorker的对象要对
sharedDataInstance做其他一些修改,而它与Worker是完全无关(或者说二者没有公共基类)的。这时就必须引入锁定Data实例的机
制,从而避免两个对象同时修改sharedDataInstance 导致的声明冲突(inconsistent
state)或读到错误数据。aspect同样能完善地解决这个问题。所有锁定所需的代码都封装在一个aspect中。

代码段2

LISTING 2
-------------------------------------------------------------------------------
01 aspect Lock {
02
03     Data sharedDataInstance;
04     Lock( Data d ) {
05         sharedDataInstance = d;
06     }
07
08     introduce Lock Data.lock;
09
10     advise Data() {
11         static after {
12             thisObject.lock = new Lock( thisObject );
13         }
14     }
15
17 }


码段2定义了一个新的aspect名为Lock。第8行通过一个叫introduce的横切面(so-called introduce
cross-cut)在Data类中引入了一个新的变量名为lock。接下来是一个advise横切面:从行10到行14,Data类的构造器被改动了,
这样每次调用构造器是advise中的代码就会被执行。这就为每个创建出的Data对象都创建了一个新的lock
aspect。如你所见,每个aspect可以有他自己的声明(sharedDataInstance??)。下一步就是advise(?)那些作用在
Data实例上的类(Worker,AnotherWorker)。为此,Lock这个aspect需扩展如下。

代码段3

LISTING 3
-------------------------------------------------------------------------------
15     boolean locked = false;
16
17     advise Worker.perform*(..), AnotherWorker.perform*(..) {
18         before {
19             if ( thisObject.sharedDataInstace.lock.locked ) // enqueue, wait
20             thisObject.sharedDataInstace.lock.locked = true;
21         }
22         after {
23             thisObject.sharedDataInstace.lock.locked = false;
24         }
25     }
26 }


里在Lock这个aspect中引入了变量locked用于记住相关的Data对象是否已经锁定。worker类也被修改了,当它们作用于Data对象时
它们会锁定该对象(行18到行20),工作完成后则解锁(行21到行23)。一个可替代的实现方式是直接在相关的Data对象中引入锁定变量
locked。

第3个例子是错误处理

代码段4

LISTING 4
-------------------------------------------------------------------------------
25     advise Worker.perform*(..), AnotherWorker.perform*(..) {
26         static catch ( Exception ex ) { ex.printStackTrace(); }
27         static finally { thisObject.sharedDataInstace.lock.locked = false; }
28     }
29 }

这段代码为各个perform方法引入两个新的advise。行26中的advise的结果是打印出perform方法中抛出的每个异常。行27则确保所有情形下锁都已被释放。
以上例子表明AOP为OO开发提供了一些有趣的概念。下面的部分是关于AOP和metalevel编程的关系,metalevel编程概念是对AOP范例的发展有着重要影响的。


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/7429/showart_29192.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP