概述
面向方面的程序设计(AOP)是一个激动人心的新规范,和已经有十几年历史的面向对象的程序设计(OOP)在软件开发上有相同的作用。 AOP和OOP不是相互竞争的技术,实际上它们相辅相成的十分融洽。 面向对象的程序设计对于建模常见的对象等级体系非常有用。 它的不足之处在于处理跨多个非关联对象模型的常见情况;这时就有AOP的用武之地了。 AOP答应你跨关联,使用单独的、彼此之间非常不同的对象模型。 它答应你层次化--而不是嵌入--函数,以便代码更易读、更便于维护。 我们喜欢把面向对象的程序设计想象成为自顶向下的软件开发,而面向方面的程序设计则是自左向右;它们是完全正交的技术,彼此之间相辅相成的十分融洽。
面向对象的程序设计的手段是继续、封装和多态性,而面向方面的程序设计的组件是通知/监听器(advice/interceptor)、引入(introdUCtion)、元数据(metadata)和切入点(pointcut) 。 让我们看看这些定义。
通知/监听器(advice/interceptor)
一个通知是被某一事件触发的程序逻辑。 它是可以被插入一个方法调用者和实际的方法之间的行为。 通知实际上是面向方面的程序设计的要害。这些构造答应你定义横切(cross-cutting)行为。通知答应你透明地应用象记录和度量这样的事到现有的对象模型中。
在JBoss AOP中,我们使用监听器实现通知。你可以定义监听器监听方法调用、构造器调用和字段访问。稍后,我们将研究如何应用这些监听器到一个现有的对象模型中。
引入
引入是一种添加方法或者字段到一个现有类的方法。它们甚至答应你改变一个现有类目前实现的接口并且引入一个混合类实现这些新接口。
引入答应你把多继续带到简单的Java类中。引入的一个重要的使用实例就是你有一个想有运行时间接口的方面。你想跨不同的对象层次应用你的方面,但是你仍然想应用程序开发者能够调用指定方面API。
Apple apple = new Apple();
LoggingAPI logging = (LoggingAPI)apple;
Apple.setLoggingLevel(VERBOSE);
引入可以是一个把新API附加于一个现有对象模型的方法。
元数据
元数据是可以附属于一个类的附加信息,或者以静态方式或者在运行时间。当你可以动态地把元数据附上到一个对象给定的实例中的时候,它将更加有效。当你正在编写可用于任何对象的一般的方面的时候,元数据显得非凡重要,但是程序逻辑必须知道指定类的信息。元数据被使用的一种很类似的情况是EJB规范。在EJB XML配置描述符中,你在一个每方法的基础上定义事务属性。应用程序服务器知道何时何地开始、暂停或者委托一个事务,因为你已经定义Required、RequiresNew、Supports等方法。在你的EJB类和事务治理程序绑定的元数据里,是bean的XML配置文件。
C#已经把元数据构建入语言中。XDoclet是另一个正在工作的很好的元数据的例子。假如你曾经用过XDoclet来生成EJB文件和配置描述符,你肯定知道元数据强大的功能。Java Community Process(JCP)达成协议,元数据被添加进JDK 1.5 (见JSR175)。直到JSR 175真正成为一种规范,一个好的AOP框架才能提供一个机制,声明在运行时间有效的类级元数据。
切入点
假如监听器,引入和元数据是面向方面的程序设计的特性,那么切入点就是把这些特性联系起来的纽带。切入点告诉面向方面的程序设计框架,哪个监听器将和哪个类捆绑在一起,哪些元数据将用于哪些类,或者引入将被导入到哪些类中。 切入点定义能够用于你的应用程序的类的各种面向方面的程序设计特性。
工作中的面向方面的程序设计
例子1、使用监听器
JBoss 4.0带有一个面向方面的程序设计框架。这个框架和JBoss应用程序服务器紧密地整合,但是你还可以在你自己的应用程序上单独运行它。你只有看到它如何工作,才能真正明白一个概念,所以让我们使用JBoss AOP中的例子来说明所有这些东西是如何合作的。在本文剩余的部分,我们将使用AOP构建一个简单的追踪框架。
定义一个监听器
首先要做的是实现我们的小跟踪框架,来定义将做实际工作的监听器。 JBoss AOP中的所有的监听器必须实现org.jboss.aop.Interceptor接口。
public interface Interceptor
{
public String getName();
public InvocationResponse invoke(Invocation invocation) throws Throwable;
}
JBoss AOP中被监听的所有字段、构造器和方法被转化为一个普通的Invocation调用。方法参数被装入一个Invocation对象,然后一个方法、字段访问或者构造器的返回值被装入一个InvocationResponse对象。Invocation对象还驱动监听器链。为了解释清楚,我们来看看在一个例程中所有这些对象如何使用。