AspectJ——切入点语法之限制连接点的作用域
Posted KLeonard
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AspectJ——切入点语法之限制连接点的作用域相关的知识,希望对你有一定的参考价值。
限制连接点的作用域
在定义切入点的时候,我们经常遇到的需求是:基于所关注的程序作用域,限制捕获连接点的范围。
本节将介绍within
以及withincode
的用法。within
可以指定切入点的作用域在包中或者类中,withincode
可以通过方法签名限制连接点的作用域在方法中。
0.捕获特定类中的所有连接点
首先,我们使用within(TypePattern)
切入点来捕获特定类中的所有连接点,它的语法如下:
pointcut [切入点名字](想要获取的参数): within(类名);
要注意的几点:
within(TypePattern)
切入点捕获指定类作用域中的所有连接点。within(TypePattern)
切入点极少单独使用,它通常与其他切入点结合使用,用于减少将要捕获连接点。within(TypePattern)
可以包含通配符,用于选择不同类上的一系列连接点。
我们在Test9
包下进行测试。
首先创建业务类Service
,如下:
package Test9;
public class Service
protected static String name = "Gavin John";
private String firstname = "Gavin";
private String lastname = "John";
public String getFirstname()
return firstname;
public void setFirstname(String firstname)
this.firstname = firstname;
public String getLastname()
return lastname;
public void setLastname(String lastname)
this.lastname = lastname;
public void test(int a, float b)
System.out.println("a + b = " + (a + b));
接着,创建测试类Main
,进行测试:
package Test9;
public class Main
public static void main(String[] args)
Service service = new Service();
System.out.println(service.getFirstname());
System.out.println(service.getLastname());
service.setLastname("Jack");
service.test(3, 3.4F);
最后,我们创建切面WithinAspect
,如下:
package Test9;
public aspect WithinAspect
pointcut withinService(): within(Service);
before(): withinService()
System.out.println();
System.out.println(thisJoinPoint.getKind());
System.out.println("Signature: " + thisJoinPoint.getSignature());
System.out.println("Source Line: " + thisJoinPoint.getSourceLocation());
在该切面中,我们创建了withinService
切入点,该切入点捕获所有在Service
类中的连接点。并且为该切入点织入前置通知,在通知中我们打印了当前连接点的类型、签名以及在源代码中的位置。
运行结果如下:
由于Service
类中的连接点非常多,所以这里只截取了一部分运行结果。从运行结果中可以看到,我们捕获了出现在Service
类中的所有连接点,包含staticinitialization
、field-set
、constructor-execution
等各种连接点。
1.捕获特定包中的所有连接点
在上例中,我们捕获了Service
类中的所有连接点,现在假如我们要捕获Test9
包下的所有连接点,该怎么做呢?
这里我们只需要简单修改切入点即可,如下,我们使用通配符表达式Test9.*
来表示Test9
包下的所有类。
package Test9;
public aspect WithinAspect
pointcut withinService(): within(Test9.*);
before(): withinService()
System.out.println();
System.out.println(thisJoinPoint.getKind());
System.out.println("Signature: " + thisJoinPoint.getSignature());
System.out.println("Source Line: " + thisJoinPoint.getSourceLocation());
但是,如果我们此时运行程序,会得到出错的结果,如下:
报了NoAspectBoundException
异常,这是为什么呢?这是因为,我们的切面WithinAspect
也位于Test9
包下,所以我们的切入点表达式Test9.*
自然也包含了切面本身,也就是说切面也会捕获切面自身的切入点,并为其织入通知。
所以,在切面初始化的时候,切面初始化的连接点被捕获到,这时候要运行通知代码,而此时切面初始化并没有完成,通知自然也就不存在,所以就抛出了异常。简单来说,这个异常的原因就是,切面来横切并通知切面自身的时候出现了矛盾的情况。
我们通过!within(TypePattern)
来将该切面排除在外即可,这里感叹号!
表示逻辑非
,即将其后面表达式的意义取反。如下:
package Test9;
public aspect WithinAspect
pointcut withinService(): within(Test9.*) && !within(WithinAspect);
before(): withinService()
System.out.println();
System.out.println(thisJoinPoint.getKind());
System.out.println("Signature: " + thisJoinPoint.getSignature());
System.out.println("Source Line: " + thisJoinPoint.getSourceLocation());
within(Test9.*) && !within(WithinAspect)
表示在Test9
包下的所有类,但是排除了WithinAspect
。此时可以成功运行。运行结果就是捕获了所有在Service
类和Main
类中的连接点。这里展示了一小部分结果:
2.捕获特定方法内的所有连接点
我们使用withincode(Signature)
切入点来捕获与特定签名匹配的方法内的所有连接点。其语法是:
pointcut [切入点名字](要获取的参数): withincode(<可选的修饰符> 类名.方法名(参数列表));
要注意的几点是:
withincode(Signature)
切入点指定了特定方法作用域内的所有连接点。withincode(Signature)
切入点很少单独使用。一般与其他切入点结合使用,用于减少将要捕获连接点。Signature
可以包含通配符,用于选择跨越不同类不同方法上的一系列连接点。withincode
与within
的区别就是withincode
用于指定方法,而within
用于指定类。
我们在Test10
包下进行测试。
其中Service
类与Main
类与上例中的一样,这里不再赘述。我们在这里新建切面WithincodeAspect
,如下:
package Test10;
public aspect WithincodeAspect
pointcut withinCodePointcut(): withincode(* Main.main(*));
before(): withinCodePointcut()
System.out.println();
System.out.println(thisJoinPoint.getKind());
System.out.println("Signature: " + thisJoinPoint.getSignature());
System.out.println("Source Line: " + thisJoinPoint.getSourceLocation());
在该切面中,我们使用withincode(* Main.main(*))
捕获了Main
类中的main
方法中的所有连接点。这里截取一部分运行结果:
以上是关于AspectJ——切入点语法之限制连接点的作用域的主要内容,如果未能解决你的问题,请参考以下文章
AspectJ——切入点语法之thistargetargsif以及逻辑运算