概述
面向方面编程(aspect-oriented programming, aop)是一个令人兴奋的新模式。就开发软件系统而言,它的影响力将会和有15到20年的面向对象一样。面向方面编程和面向对象编程不但不是互相竞争的技术而且是可以很好的互补。面向对象编程主要用于为同一对象层次的公用行为建模。它的弱点是将公共行为应用于多个无关对象模型之间。而这恰恰是aop适合的地方。aop允许定义交叉的关系,那些关系应用于跨国分开的,非常不同的对象模型。aop允许你层次化功能性而不是嵌入功能性,那使得代码有更好的可度性和易于维护性。我喜欢认为oop是自上而下的软件开发,而aop是自左而右的软件开发,它们是完全直交的技术,并且互相很好的补充。
在oop的工具里是继承,封装和多态,而aop的组件是通知/拦截器,导言,元数据和pintcuts.让我们看一下这些定义。
通知/拦截器
一个通知是一个逻辑,这个逻辑有特定的事件触发。它是行为,这个行为能够被插入在调用者和被调用者之间,在一个方法调用者和实际的方法之间。通知是aop真正的关键。通知允许你去透明的应用一些事物,像日志和记录到一个存在的对象模型。
在 jboss aop中,我们用拦截器是实现了通知。你能够定义拦截器,它拦截方法调用,构造器调用和域访问。后面,我们将阐明怎样应用这些拦截器到一个存在的对象模型。
导言
导言是一个增加方法或者域到一个存在的类中的途径。它们甚至允许你改变当前存在的类是显的接口,并且引入一个混合的类,这个类是实现了新的接口。导言允许你带入多继承到一般的java类。导言一个主要的用例是当你有一个方面,你想让这个方面有一个运行时间借口时。你想应用你的方面跨越不同的对象层次,但是你仍然要应用开发者去能够调用特定方面的apis.
apple apple = new apple();
loggingapi logging = (loggingapi)apple;
apple.setlogginglevel(verbose);
导言能够是一个方法,它将一个新的api绑定到一个存在的对象模型。
元数据
元数据是能够绑定到一个类的附加信息,在静态或者运行时间。元数据更加有力力量的是,你能够动态绑定元数据到一个给定的对象实例。元数据非常强大的,当你真正编写应用于任何对象的一般方面,而逻辑需要知道制定类的信息时。在使用的一个好的元数据类比就是ejb规范。在ejb的xml发布描述符中,你需要定义基于每一个方法的事务属性。应用服务器指导什么时候,什么地方开始,挂起或者提交一个事务,因为你在bean的xml的配置文件中的元数据内已经定义如方法:required,requiresnew,support等等,它们绑定在你的ejb类和事务管理之间。
c#把元数据成为了这个语言的组成部分。xdoclet是另一个动作的元数据的例子。如果你曾经用过xdoclet生成过ejb文件和发布描述符,你就会知道元数据的力量。在jdk1.5中,当元数据被加入java语言中,jcp一致同意。(见jsr175)。尽管直到jsr175成为了事实,一个好的aop框架也应该提供一种机制去定义在运行时间有效的类级元数据。
pointcuts
如果拦截器,导言和元数据是aop的特征,那么pointcuts就是粘合剂。pointcuts告诉aop框架,那些拦截器绑定到那些类, 什么原数据将应用于那些类或者那一个导言将被传入那些类。pointcuts定义各种aop特征将怎样应用于你应用中的类。
在动作中的aop
例1.使用拦截器
jboss 4.0带了一个aop框架。这个框架和jboss应用服务器紧密地结合,但是你也能够在你的应用中,单独的运行它。直到你看了动作中看到它,你才会完全的理解这个概念,所以让我们用一个来自于jboss aop的例子,来说明这个模块所有的部分是如何一起工作的。在这章余下的部分,我们将建立一个例子来跟踪使用aop的框架。
定义一个拦截器
为了实现我们对于框架的跟踪,我们必须作的第一件事是定义一个拦截器,它将作实际的工作。在jboss aop中,所有的拦截器必须实现org.jboss.aop.interceptor 接口。
public interface interceptor
{
public string getname();
public invocationresponse invoke(invocation invocation) throws throwable;
}
import org.jboss.aop.*;
import java.lang.reflect.*;
public class tracinginterceptor implements interceptor
{
public string getname() { return tracinginterceptor; }
public invocationresponse invoke(invocation invocation)
throws throwable
{
string message = null;
if (invocation.gettype() == invocationtype.method)
{
method method = methodinvocation.getmethod(invocation);
message = method: + method.getname();
}
else if (invocation.gettype() == invocationtype.constructor)
{
constructor c = constructorinvocation.getconstructor(invocation);
message = constructor: + c.tostring();
}
else
{
// do nothing for fields. just too verbose.
//对于域什么也不做。太繁琐。
return invocation.invokenext();
}
system.out.println(entering + message);
// continue on. invoke the real method or constructor.
// 继续。调用真正的方法或者构造器
invocationresponse rsp = invocation.invokenext();
system.out.println(leaving + message);
return rsp;
}
}
<?xml version="1.0" encoding="utf-8">
<aop>
<interceptor-pointcut class="pojo">
<interceptors>
<interceptor class="tracinginterceptor" />
</interceptors>
</interceptor-pointcut>
</aop>
public class pojo
{
public pojo() {}
public void helloworld() { system.out.println(hello world!); }
public static void main(string[] args)
{
pojo pojo = new pojo();
pojo.helloworld();
}
}
entering method: main
entering constructor: public pojo()
leaving constructor: public pojo()
entering method: helloworld
hello world!
leaving method: helloworld
leaving method: main
$ cd oreilly-aop/example1
$ export classpath=.;jboss-common.jar;jboss-aop.jar;javassist.jar
$ javac *.java
$ java -djava.system.class.loader=org.jboss.aop.standalone.systemclassloader pojo
<?xml version="1.0" encoding="utf-8">
<aop>
<class-metadata group="tracing" class="pojo">
<method name="(get.*)(set.*)">
<filter>true</filter>
</method>
<method name="main">
<filter>true</filter>
</method>
</class-metadata>
</aop>
Java Asp PHP .Net XML C/C++ CGI VB Jsp J2ee J2se J2me EJB Servlet Tomcat Resin Struts Weblogic Eclipse ANT GUI JMS Web servise IDEA Webphere Hibernate Spring Jboss Applet Swing Socket Javamail Perl Ajax P2P 安全 模式 框架 测试 开源 游戏
Windows XP Windows 2000 Windows 2003 Windows Me Windows 9.x Linux UNIX 注册表 操作系统 服务器 应用服务器