AspectJ切入点语法

时间:2022-03-08 09:47:33
类型匹配语法
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。

AspectJ切入点语法

@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();

部分测试摘自http://www.cnblogs.com/yangyquin/p/5582911.html