为了实现我们对于框架的跟踪,我们必须作的第一件事是定义一个拦截器,它将作实际的工作。在JBOSS AOP中,所有的拦截器必须实现org.jboss.aop.Interceptor 接口。
在JBoss AOP中,被拦截的所有域,构造器和方法被转成一般的invoke调用。方法的参数被填入一个Invocation对象,并且方法的返回值,域的存取或者构造器被填入一个InvocationResponse对象。这个Invocation对象也驱动这个拦截链。为了清楚地说明这个,让我们看一下,在这个例子中,所有的对象是如何配合到一起的。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; } }
绑定拦截器
好了,这样我们就定义了拦截器。但是怎么绑定这个拦截器到实际的类?为了做这个,我们需要定义一个pointcut。对于JBoss AOP, pointcuts 是在一个XML文件中定义的。让我们看一下这看起来象什么。
上面的pointcut绑定TracingInterceptor到一个叫做POJO的类。这看起来有一点麻烦;我们不得不为每一个想跟踪的类创建一个 pointcut吗?幸运的是,interceptor-pointcut的类属性可以用任何的正规表达式。所以如果你想跟踪由JVM载入的类,类表达式将变为 .*。如果你仅仅想跟踪一个特定的包,那么表达式将是com.acme.mypackge.*。
当单独运行JBoss AOP时,任何符合 META-INF/jboss-aop.xml模式的XML文件将被JBoss AOP 运行时间所载入。如果相关的路径被包含在任何JAR或你的CLASSPATH的目录中,那个特定的XML文件将在启动时,由JBoss AOP 运行时间所载入。
运行这个例子,我们将用上面定义的pointcut去运行例子。POJO类看起来如下:
你能够在这里下载JBoss AOP和离子代码。编译和执行:[code]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(); } } [/code] TracingInterceptor将拦截对main(),POJO()和helloWorld()的调用。输出看起来如下: Entering method: main Entering constructor: public POJO() Leaving constructor: public POJO() Entering method: helloWorld Hello World! Leaving method: helloWorld Leaving method: main
JBoss AOP 对绑定的拦截器做字节码操作。因为没有编译步骤,AOP运行时间必须有ClassLoader的总控。如果你正运行在非JBoss应用服务器,你必须用JBoss制定的一个类载入器覆盖系统的类载入器。$ 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
TraceingInterceptor不跟踪域访问,因为它有一点繁琐。对于开发者,实现get()和set()方法去封装域访问是一个一般的实践。如果TracingInterceptor能够过滤出,并且不跟踪这些方法,那是非常好的。这个例子显示你能够用JBoss AOP 元数据去实现基于任一方法的过滤。一般,元数据用于更复杂的事情,如定义事务属性,每个方法的安全角色或者持久性映射,但是这个例子应该足够说明元数据能够怎样用在 AOP使能的应用中。