增强织入的顺序
一个连接点可以同时匹配多个切点,切点对应的增强在连接点上的织入顺序到底是如何安排呢?这个问题需要分三种情况讨论:
如果增强在同一个切面类中声明,则依照增强在切面类中定义的顺序进行织入;
如果增强位于不同的切面类中,且这些切面类都实现了org.springframework.core.Ordered接口,则由接口方法的顺序号决定(顺序号小的先织入);
如果增强位于不同的切面类中,且这些切面类没有实现org.springframework.core.Ordered接口,织入的顺序是不确定的。
我们可以通过下图描述这种织入的规则:
图 9 增强织入顺序
切面类A和B都实现为Ordered接口,A切面类对应序号为1,B切面类对应序号为2,A切面类按顺序定义了3个增强,B切面类按顺序定义两个增强,这5个增强对应的切点都匹配某个目标类的连接点,则增强织入的顺序为图中虚线所示。
访问连接点信息
AspectJ使用org.aspectj.lang.JoinPoint接口表示目标类连接点对象,如果是环绕增强时,使用org.aspectj.lang.ProceedingJoinPoint表示连接点对象,该类是JoinPoint的子接口。任何一个增强方法都可以通过将第一个入参声明为JoinPoint访问到连接点上下文的信息。我们先来了解一下这两个接口的主要方法:
1)JoinPoint
java.lang.Object[] getArgs():获取连接点方法运行时的入参列表;
Signature getSignature() :获取连接点的方法签名对象;
java.lang.Object getTarget() :获取连接点所在的目标对象;
java.lang.Object getThis() :获取代理对象本身;
2)ProceedingJoinPoint
ProceedingJoinPoint继承JoinPoint子接口,它新增了两个用于执行连接点方法的方法:
java.lang.Object proceed() throws java.lang.Throwable:通过反射执行目标对象的连接点处的方法;
java.lang.Object proceed(java.lang.Object[] args) throws java.lang.Throwable:通过反射执行目标对象连接点处的方法,不过使用新的入参替换原来的入参。
让我们来看一个具体的实例:
代码清单 9 TestAspect:访问连接点对象
package com.baobaotao.aspectj.advanced;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class TestAspect ...{
@Around("execution(* greetTo(..)) && target(com.baobaotao.NaiveWaiter)") ①环绕增强
public void joinPointAccess(ProceedingJoinPoint pjp) throws Throwable...{ ②声明连接点入参
System.out.println("------joinPointAccess-------");
③ 以下两行访问连接点信息
System.out.println("args[0]:"+pjp.getArgs()[0]);
System.out.println("signature:"+pjp.getTarget().getClass());
pjp.proceed(); ④ 通过连接点执行目标对象方法
System.out.println("-------joinPointAccess-------");
}
}
在①处,我们声明了一个环绕增强,在②处增强方法的第一个入参声明为PreceedingJoinPoint类型(注意一定要在第一个位置),在③处,我们通过连接点对象pjp访问连接点的信息。在④处,我们通过连接点调用目标对象的方法。
执行以下的测试代码:
String configPath = "com/baobaotao/aspectj/advanced/beans.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
Waiter naiveWaiter = (Waiter) ctx.getBean("naiveWaiter");
naiveWaiter.greetTo("John");
输出以下的信息:
------joinPointAccess-------
args[0]:John
signature:class com.baobaotao.NaiveWaiter
NaiveWaiter:greet to John... ①对应pjp.proceed();
-------joinPointAccess-------