AspectJ切入点语法
类型匹配语法
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();