类型匹配语法
AspectJ类型匹配的通配符:
*:匹配任何数量字符;
..:匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数。
+:匹配指定类型的子类型;仅能作为后缀放在类型模式后边。
java代码:
java.lang.String 匹配String类型;
java.*.String 匹配java包下的任何“一级子包”下的String类型;
如匹配java.lang.String,但不匹配java.lang.ss.String
java..* 匹配java包及任何子包下的任何类型;
如匹配java.lang.String、java.lang.annotation.Annotation
java.lang.*ing 匹配任何java.lang包下的以ing结尾的类型;
java.lang.Number+ 匹配java.lang包下的任何Number的自类型;
如匹配java.lang.Integer,也匹配java.math.BigInteger
- 注解:可选,方法上持有的注解,如@Deprecated;
- 修饰符:可选,如public、protected;
- 返回值类型:必填,可以是任何类型模式;“*”表示所有类型;
- 类型声明:可选,可以是任何类型模式;
- 方法名:必填,可以使用“*”进行模式匹配;
- 参数列表:“()”表示方法没有任何参数;“(..)”表示匹配接受任意个参数的方法,“(..,java.lang.String)”表示匹配接受java.lang.String类型的参数结束,且其前边可以接受有任意个参数的方法;“(java.lang.String,..)” 表示匹配接受java.lang.String类型的参数开始,且其后边可以接受任意个参数的方法;“(*,java.lang.String)” 表示匹配接受java.lang.String类型的参数结束,且其前边接受有一个任意类型参数的方法;
- 异常列表:可选,以“throws 异常全限定名列表”声明,异常全限定名列表如有多个以“,”分割,如throws java.lang.IllegalArgumentException, java.lang.ArrayIndexOutOfBoundsException。
@Before(args(param) && target(bean) && @annotation(secure)",
argNames="jp,param,bean,secure")
public void before5(JoinPoint jp, String param,
IPointcutService pointcutService, Secure secure) {
……
}
访问连接点信息
AspectJ使用org.aspectj.lang.JoinPoint接口表示目标类连接点对象,如果是环绕增强时,使用org.aspectj.lang.ProceedingJoinPoint表示连接点对象,该类是JoinPoint的子接口,任何一个增强方法都可以通过将第一个入参声明为JoinPoint访问到连接点上下文的信息。
直接通过 args[‘index’] = ... 方式来修改,再通过 Object retVal = pjp.proceed(args);
return retVal;
即可改变并传入参数;
Aspect
public class TestAspect3 {
@Around("execution(* greetTo(..)) && target(com.yyq.aspectJAdvanced.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---");
}
}
@Test
public void pointAspectJTest3() {
String configPath = "com\\yyq\\aspectJAdvanced\\beans.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
Waiter naiveWaiter = (Waiter) ctx.getBean("naiveWaiter");
naiveWaiter.greetTo("Andy");
}
输出结果:
---joinPointAccess---
args[0]:Andy
signature:class com.yyq.aspectJAdvanced.NaiveWaiter
NaiveWaiter:greet to Andy...
---joinPointAccess---
绑定代理对象
使用this()或target()可绑定被代理对象实例,在通过类实例名绑定对象时,还依然具有原来连接点匹配的功能,只不过类名是通过增强方法中同名入参的类型间接决定罢
@Aspect
public class TestAspect5 {
@Before("this(waiter)")
public void bindProxyObj(Waiter waiter){
System.out.println("---bindProxyObj---");
System.out.println(waiter.getClass().getName());
System.out.println("---bindProxyObj---");
}
}
如果第一个参数类型是JoinPoint、ProceedingJoinPoint或JoinPoint.StaticPart类型,应该从“argNames”属性省略掉该参数名(可选,写上也对),这些类型对象会自动传入的,但必须作为第一个参数
@Aspect
public class TestAspect7 {
@AfterReturning(value = "target(com.yyq.aspectJAdvanced.SmartSeller)", returning = "retVal", throwing = "iae")
public void bindReturnValue(int retVal,IllegalArgumentException iae) {
System.out.println("---bindReturnValue---");
System.out.println("returnValue:" + retVal);
System.out.println("exception:" + iae.getMessage());
System.out.println("---bindReturnValue---");
}
}
@Before(value="execution(* test(*)) && args(param)", argNames="param")
public void before1(String param) {
System.out.println("===param:" + param);
}
@Before(value=" args(param)", argNames="param") //明确指定了
public void before1(JoinPoint jp, String param) {
System.out.println("===param:" + param);
}
绑定返回值 抛出对象
在后置增强中,我们可以通过returning绑定连接点方法的返回值。
@Aspect
public class TestAspect7 {
@AfterReturning(value = "target(com.yyq.aspectJAdvanced.SmartSeller)", returning = "retVal", throwing = "iae")
public void bindReturnValue(int retVal,IllegalArgumentException iae) {
System.out.println("---bindReturnValue---");
System.out.println("returnValue:" + retVal);
System.out.println("exception:" + iae.getMessage());
System.out.println("---bindReturnValue---");
}
}
/**
* 定义切入点(包含切入点表达式和切点签名).
*/
@Pointcut("execution(public * *(org.mengyun.tcctransaction.api.TransactionContext,..))||@annotation(org.mengyun.tcctransaction.Compensable)")
public void transactionContextCall() {
}
/**
* 定义环绕通知(在一个方法执行之前和执行之后运行,第一个参数必须是 ProceedingJoinPoint类型,方法的调用者得到的返回值就是环绕通知返回的值)
* @param pjp
* @throws Throwable
*/
@Around("transactionContextCall()")
public Object interceptTransactionContextMethod(ProceedingJoinPoint pjp) throws Throwable {
LOG.debug("==>interceptTransactionContextMethod(ProceedingJoinPoint pjp)");
//TODO
}
//通过Method对象的getAnnotation(clazz)方法获取注解
//ProceedingJoinPoint pjp
//获取方法返回值类型
Object[] args = pjp.getArgs();
Class<?>[] paramsCls = new Class<?>[args.length];
for (int i = 0; i < args.length; ++i) {
paramsCls[i] = args[i].getClass();
}
//获取方法
Method method = pjp.getTarget().getClass().getMethod(pjp.getSignature().getName(), paramsCls);
//获取注解
method = getAnnotation(clazz);
//获取返回值类型
Type t = method.getAnnotatedReturnType().getType();