面向方面编程 (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 。
评论