面向方面编程(AOP)可用来解决当今的
许多
应用需求。其中,
Eclipse基金的AspectJ
是
其中一个比较流行的AOP实现。刚开始使用AspectJ时,可能会让初学者望而怯步。在AJDT项目的领导者――Matt
Chapman的一篇新文章中,展示了如何通过使用Eclipse的AJDT插件来使AspectJ开发变得更为容易。更多关于AspectJ的信息可以
从
InfoQ的AspectJ标签
找到。
AOP词汇表
AOP,Aspect-oriented programming:面向方面编程
Core concerns:核心关注点,
Crosscutting concerns:横切关注点
Aspect:方面
Advice:通知
Pointcut:切入点
Weave:织入
Joinpoint:联结点
如果你正在进行AspectJ开发而且还没有使用Eclipse AspectJ开发工具(AspectJ Development Tools,AJDT)的话,本文会告诉你错过了什么好东西。即使你以前用过AJDT,你也能从本文中看到一些以前不知道的特性。
相关厂商 内容
越来越多的开发者正逐渐变得更加依赖功能强大的IDE。毫无疑问,人们大都还记得用Emacs或Vi编程的日子(我敢打赌有些人还在这样做),但对 不少开发者来说,像上下文助手这样的功能已经变得必不可少了――如果不用IDE你就无法写出像样的应用程序,那么你显然就是control-space一 族了(control-space是Eclipse上下文助手功能的快捷键)。
在AspectJ这样的语言里,面向方面编程提供了强大的能力并改善了模块性,但是如果没有合适的工具将会减弱程序的易理解性。当然,你可以通过察 看各个单独的Java代码来在一定程度上理解它要做什么,但是如果使用AspectJ,就会用到一些advice,那么你就可能看不到程序的全貌了。对于 普通的Crosscutting concerns(例如跟踪功能),对该concerns一无所知也没什么关系,但对于像安全或领域特有的concerns就不同了,因为它们可能是应用 程序的核心。因此,IDE支持AOP比支持OOP对程序开发的帮助更大。
通过这篇文章,我们将探究AJDT的一些特性,以展示该工具如何使你从AOP方法里获得更高的效率及更大的收益。
编辑器中的Crosscutting
让我们从Java代码在普通编辑器中的样子开始吧:
现在,我们把这段代码放在Eclipse Java编辑器中比较一下:
除了语法着色外,还有个主要区别,就是编辑器左右边框上的标记。右边框上的小方块是概览标记,其用途是表示左侧边框上的标记(所在行)在整个源文件中所处的位置(而且通过鼠标左键点击小方块可以定位到该位置)。左侧的标记是advice标记,表示受到before ( ),after ( )或 around ( ) advice影响的源码位置。
从上面的截屏可以看到,在paint()方法里有两行代码受到了before advice的影响。paint()方法本身的执行也受到某advice的影响。普通advice标记图标( )表示该位置的代码同时受多种advice的影响。
如果鼠标在标记上稍作停留,将会弹出一个含有更多信息的tooltip(工具提示),你也可以用鼠标右键点击该标记弹出一个"Advised By"菜单,使用该菜单可以导航到对应的advice定义处。上图中结合点标记处( )有两个"Advised By"菜单入口,说明该方法受到了before和after两个advice的双重影响,如下图所示:
AspectJ编辑器
AspectJ是对Java的扩展,Eclipse惯例是在.java文件中保持纯java代码(即使在AspectJ项目中也是这样),而 用.aj文件来存放AspectJ特有代码。比如,新的aspect将被创建在.aj文件中。这意味着Java编辑器默认还是用于.java文件,而 AspectJ编辑器是用于.aj文件的。由于AspectJ编辑器是从Java编辑器扩展而来的,因此它也可用于Java代码。
这里是一个用AspectJ编辑器打开的acpect:
AspectJ编辑器表现AspectJ代码的方式被设计成与Java编辑器表现Java代码的方式相同。例如语法着色被扩展到了像 execution,around和proceed这样的AspectJ关键字上。其他的编辑操作方式都是一样的,比如Organize Imports,Add Import,和Format。(这三者都是Eclipse Java编辑器的功能。Organize Imports:可以根据代码中所引用的类自动增加缺少的import语句或删除多余的import语句;Add Import:增加缺少的import语句;Format:可以对代码书写风格进行自动整理)
Control-Space援助
上下文助手(也叫做代码补全――Code Completion)的重要性前面已经提到了。AspectJ编辑器在aspect所定义的方法内及advice代码块内(语法上类似于方法)提供了基 于Java的代码完成功能。你可以用下面的操作依据advice参数补全代码:
在上图光标位置按下Control-Space键,编辑器会给出一个选择列表,其中包含了:局域变量、advice参数mon和ticks、 AspectJ特有变量thisJointPoint和thisJointPointStaticPart、一个aspect的静态私有属性 monitorMap、以及继承自Object的方法。
Aspect也可以代表其他类声明其属性和方法。这就是众所周知的intertype declarations(这是一种功能强大的机制,利用它可以在原有类或接口的外部增加其属性或方法),且需要不同的上下文助手完成:
这儿的aspect代码片断是为Point类定义了一个叫做hasListeners的方法。在图示的位置上,代码补全功能提供的是在Point类的上下文中,而非所在aspect的上下文中。
AJDT同样也提供了代码模板提示功能,因此你可以如下操作:键入"pc"并按下control-space键来插入pointcut声明的代码模板:
红色波浪线下划线
Java编辑器另一个重要特性是用红色波浪下划线标出你所键入代码的错误之处。AspectJ编辑器对aspect中的Java语法和 AspectJ特有语法(虽然有些限制)也采用了与Java编辑器同样的方式标出键入错误。在红色波浪下划线上停留片刻会显示一个含有更多信息的 tooltip:
大纲视图(Outline view)
Eclipse标准大纲视图显示的是当前文档的文档结构。Aspect的结构与类的文档结构相似。对AspectJ新增的节点类型有aspect、 pointcut、advice、intertype declaration以及declare statement,如下图所示。不同的图标用来表示不同的可见性,而对于aspect的advice则表示针对该advice是否有一个动态检测(也就是说,在编译期无法决定它的精确匹配时)。 Aspect也能包含正规的属性和方法。像类一样,Aspect的文档结构在你键入代码的时候就生成了(不需要保存操作),而且在包浏览器(package explorer)里展开源文件时也能看到该文档结构。
Advice装饰
Java元素(属性或方法)显示在Eclipse视图中时,都配有一个图标以说明该元素的类型,以及它的可见性。AJDT提供了一个额外的图片装饰 来指明哪些元素受到advice的影响。AJDT通过在Java元素左侧再显示一个橙色小三角形来说明其受到了某advice影响,如下图所示,其中 main、foo及bar方法都受到advice的影响。
无论何时,只要这样的Java元素显示在Eclipse视图中,这个图片装饰就会出现。这些视图包括大纲视图(outline view)、包浏览器(package explorer)、Java浏览透视图的类成员视图(members view)以及AJDT所提供的视图。
交叉引用视图(The Cross References view)
我们已经看到了AJDT如何通过增加编辑器标记和装饰advice元素来显示AspectJ的crosscutting特征。这些机制都是为了让已 有视图和编辑器能无缝地提供附加信息。但是,这些机制是“窄带”机制,有时候不能提供足够详细的信息,比如当多个advice在同一位置施加影响时,或当 我们要观察某个源文件的所有advice影响时。
这就是Cross References视图出现的理由(有时简称为"X-Ref")。当你开始使用AJDT时该视图将自动打开,或者你可以手动选择Window > Show View > Other...菜单,并从AspectJ类别里选择该视图来打开它。当然,你可以把该视图放置在透视图中任何你喜欢的位置,但是一开始建议把交叉引用视 图(Cross References view)放在大纲视图(Outline view)下面。或许你曾使用过快速打开大纲视图的方法:按下Control-O 键。对交叉引用视图也一样,你既可以通过Navigate菜单也可以通过按Alt-Shift-P键打开该视图(所有快捷键绑定都已经设置好了!)
"Cross References"的名字比较通用,因为这个视图是一个多种用途的视图,可以扩展用来显示活动编辑器所选中的当前元素的任何相关信息。在AJDT里,该视图被配置成用来显示当前元素的crosscutting关联关系。
让我们回到前面VisualiserCanvas.java的例子,该例中我们看到了在编辑器边框上增加了advice标记。这些标记说明了 advice的存在,且通过上下文菜单可显示更多的信息,但是这需要额外的动作甚至更多操作。下图是交叉引用视图所显示的paint方法:
我们可以看到paint方法自身被某before和after advice所影响,方法中的元素也受到了影响。调用Image.dispose()的方法受before advice影响,而Image的构造方法调用则被另一些advice所影响,所有这些advice都来自RenderingMonitorInfo aspect。
随着交叉引用视图加入到Java透视图中,该视图中的crosscutting详细信息总是一闪即逝,因为它随着编辑器和大纲视图所选择元素的不同 而变化,所以默认情况下,总是显示与当前元素相关的信息。如有需要,这个视图工具条上有一个按钮可以禁止这种关联。还有一个按钮用来为整个文件而非当前元 素显示crosscutting信息。
增量编译
使用成熟IDE的一个最大的好处是以减少“编辑-编译-运行-调试”这一往复过程中所消耗的时间来提高生产效率。Eclipse的Java增量编译 器做得非常好,它会根据你编辑代码所产生变化,只编译那些需要编译的内容,这个过程很快,几乎觉察不到。AJDT所使用的AspectJ编译器是基于 Eclipse Java编译器的,同样也能达到高效的目的。虽然AspectJ的crosscutting特性处理过程比较复杂,但对于类和aspect的简单变化仍然 会进行快速增量编译。但有些变化需要全面的构建(增量编译就不能用了),比如当pointcut或已被织入的advice发生变化时,就要全面构建了。
@AspectJ
目前为止,我们所看到的aspect声明是代码风格的,我们使用了诸如aspect, pointcut 和 before这样的语言关键字将这些aspect声明在.aj文件中。AspectJ还支持注释风格的声明,称之为@AspectJ风格。在这种风格下, 用正规的Java类和方法与Java 5注释相结合来声明aspect。例如,不用“pointcut”关键字,而是用该切入点的名称来创建一个方法,这个切入点可能是一个@Before注 释。注释的值是一个字符串,它是pointcut表达式。
AJDT是支持这种@AspectJ风格的。此时,对于该风格,交叉引用视图(Cross References view)同样可以显示crosscutting关联关系,标记也会正确显示在编辑器上。Add Import 操作可以帮助生成AspectJ所定义的注释,而键入内容错误显示可以帮助检查基本语法,尽管该功能无法涉及到对注释中字符串内容的合法性的查。这的确是 @AspectJ声明式风格的一个缺点,但至少在源文件被保存并编译后,所有错误都会被标上红色波浪下划线,并有tooltip提示:
上手
在Eclipse上安装AJDT最简单的方法是定义一个更新站点(Update Site) (通过菜单Help > Software Updates > Find and Install...)。您想得到正确的更新站点URL,可以看AJDT的下载页面。那儿有适用于最新Eclipse发行版的AJDT发行版,也有适用老 版Eclipse的版本。如果你想试试最新版AJDT特性或想尝试最新构建的Eclipse版本,网站上还有频繁发布的AJDT开发构建版可供使用。
你可以使用适当的向导或工具条图标创建一个新的AspectJ项目,或者你可以在包浏览器视图上右键点击项目,并从上下文菜单中选择AspectJ Tools > Convert to AspectJ Project,将一个Java工程转换为AspectJ项目。创建新类、新包等过程与Java项目相同,另外可用New Aspect向导用来创建一个新的aspect。
内建例程
为方便起见,AJDT打包进了几个例子项目,使用一个简单的向导即可将这些例子导入到你的workspace中。本文中的许多截屏都来自这些例子项 目。点击工具条上的New按钮,或选择File > New > Other...并展开AspectJ分类。例子被划分为两类。第一类,AspectJ例程(AspectJ Examples)包含了随编译器分发的、且在《AspectJ Programming Guide》第3章讲到的例程。第二类是AspectJ插件例程(AspectJ Plug-in Examples)。这是最近增进来的,用以展示开发Eclipse 插件时使用aspect的一些方法。到AJDT 1.4为止这个分类中只有一个例子,将来的版本会有更多的例子添加进去。当前的这个例子,叫做 Progress Monitor Checker,展示了aspect可以用来测试那些使用了Eclipse progress monitors的插件是否遵循某些规则,这些规则是API所要求的且在一篇Eclipse Corner Article中描述过的。
结论
从这篇文章中我们看到了AspectJ编辑器所提供了成熟功能来帮助开发aspect,以及标记和交叉引用视图是如何显示细节信息并支持 crosscutting结构导航的。增量编译提高了开发过程的效率,Eclipse Java调试器还可以被用作AspectJ编译器来产生正规的字节码(如果要在around advice里设置断点,需要在AspectJ 编译器设置中关闭 inlining选项)。AJDT还提供超越本文范围的更高级的能力,包括为装载时织入(load-time weaving)的初始配置,aspect可视透视图,crosscutting比较工具,对支持开发和使用aspect类库的支持,以及开发那些使用 AspectJ的 Eclipse插件的相关功能。
请访问AJDT网站 以获得更多内容,包括demos、新特性、下载。如果你有任何问题,网站上还提供了AJDT新闻组详细资料。AJDT是一个Eclipse.org的开源工具项目,按照EPL规定发行。
查看英文原文: Making AspectJ development easier with AJDT
作者简介: Matt Chapman是英国IBM Husley实验室的软件工程师。他领导了Eclipse.org的AJDT项目,该项目开发了一个集成开发环境以使开发者能从AOP中获得最大利益。他经常出席诸如EclipseCon和AOSD之类的会议。
译者简介: 宋玮,有多年软件开发经验,从2002年开始就使用Java,在各个项目开发过程中先后使用过Struts、Oracle ADF、AspectJ等。最近正在使用Spring及Ruby on Rails,对敏捷方法有比较大的兴趣并做过一些尝试。他的blog为http://www.donews.net/victorsong 。与InfoQ中文站分享内容,请邮件至china-editorial@infoq.com 。