Spring AOP中@Pointcut切入点表达式详解

目录

一、瞅一眼标准的AspectJ Aop的pointcut的表达式

二、SpringAop的十一种AOP表达式

三、演示使用

1、execution:

2、within:

3、this:

4、target:

5、args:

6、@target:

7、@args:

8、@within:

9、@annotation:

10、reference pointcut:

11、bean:

四、类型匹配语法

五、表达式的组合


一、瞅一眼标准的AspectJ Aop的pointcut的表达式

标准的AspectJ Aop的pointcut的表达式类型是很丰富的

见org.aspectj.weaver.tools.PointcutPrimitive
这个枚举类:

二、SpringAop的十一种AOP表达式

SpringAop只支持标准的AspectJ Aop的pointcut的表达式类型其中的10种,外加Spring Aop自己扩充的一种一共是11(10+1)种类型的表达式,分别如下。

1.execution:一般用于指定方法的执行,用的最多。
2.within:指定某些类型的全部方法执行,也可用来指定一个包。
3.this:Spring Aop是基于动态代理的,生成的bean也是一个代理对象,this就是这个代理对象,当这个对象可以转换为指定的类型时,对应的切入点就是它了,Spring Aop将生效。
target:当被代理的对象可以转换为指定的类型时,对应的切入点就是它了,Spring Aop将生效。

4.reference pointcut:(经常使用)表示引用其他命名切入点,只有@ApectJ风格支持,Schema风格不支持
5.args:当执行的方法的参数是指定类型时生效。
6.@args:当执行的方法参数类型上拥有指定的注解时生效。
7.@within:与@target类似,看官方文档和网上的说法都是@within只需要目标对象的类或者8.父类上有指定的注解,则@within会生效,而@target则是必须是目标对象的类上有指定的注解。而根据笔者的测试这两者都是只要目标类或父类上有指定的注解即可。
9.@annotation:当执行的方法上拥有指定的注解时生效。
10.@target:当代理的目标对象上拥有指定的注解时生效。
11.bean:当调用的方法是指定的bean的方法时生效。(Spring AOP自己扩展支持的)

注意Pointcut定义时,还可以使用&&、||、! 这三个运算。进行逻辑运算。可以把各种条件组合起来使用

三、演示使用

1、execution:

execution是使用的最多的一种Pointcut表达式,用于切方法。

  1. //表示匹配所有方法
  2. 1)execution(* *(..))
  3. //表示匹配com.lasse.UserService中所有的公有方法
  4. 2)execution(public * com.lasse.UserService.*(..))
  5. //表示匹配com.fsx.run包及其子包下的所有方法
  6. 3)execution(* com.lasse..*.*(..))

当我们的切面很多的时候,我们可以把所有的切面放到单独的一个类去,进行统一管理,比如下面:

  1. //集中管理所有的切入点表达式
  2. public class Pointcuts {
  3. @Pointcut("execution(* *Message(..))")
  4. public void logMessage(){}
  5. 。。。
  6. }

引用方式

  1. @Before("com.lasse.Pointcuts.logMessage()")
  2. public void before(JoinPoint joinPoint) {
  3. System.out.println("do something");
  4. }

2、within:

within是用来指定类型的,指定类型中的所有方法将被拦截。不拦截其子类,所以切接口没用。

  1. //此处只能写实现类
  2. @Pointcut("within(com.lasse.service.impl.AServiceImpl)")
  3. public void pointCut() {
  4. }
  5. //匹配包以及子包内的所有类
  6. @Pointcut("within(com.lasse.service..*)")
  7. public void pointCut() {
  8. }

3、this:

Spring Aop是基于代理的,this就表示代理对象。this类型的Pointcut表达式的语法是this(type),当生成的代理对象可以转换为type指定的类型时则表示匹配。基于JDK接口的代理和基于CGLIB的代理生成的代理对象是不一样的。

  1. // 拦截到AService所有的子类的所有外部调用方法
  2. @Pointcut("this(com.lasse.service.AService*)")
  3. public void pointCut() {
  4. }

4、target:

Spring Aop是基于代理的,target则表示被代理的目标对象。当被代理的目标对象可以被转换为指定的类型时则表示匹配。
注意:和上面不一样,这里是target,因此如果要切入,只能写实现类了

  1. @Pointcut("target(com.lasse.service.impl.AServiceImpl)")
  2. public void pointCut() {
  3. }

5、args:

args用来匹配方法参数的。

    1、“args()”匹配任何不带参数的方法。
    2、“args(java.lang.String)”匹配任何只带一个参数,而且这个参数的类型是String的方法。
    3、“args(…)”带任意参数的方法。
    4、“args(java.lang.String,…)”匹配带任意个参数,但是第一个参数的类型是String的方法。
    5、“args(…,java.lang.String)”匹配带任意个参数,但是最后一个参数的类型是String的方法。
 

  1. @Pointcut("args()")
  2. public void pointCut() {
  3. }

6、@target:

@target匹配当被代理的目标对象对应的类型及其父类型上拥有指定的注解时。

  1. //能够切入类上(非方法上)标准了@MyAnno注解的所有外部调用方法
  2. @Pointcut("@target(com.lasse.anno.MyAnno)")
  3. public void pointCut() {
  4. }

7、@args:

@args匹配被调用的方法上含有参数,且对应的参数类型上拥有指定的注解的情况。
例如:

  1. // 匹配**方法参数类型上**拥有MyAnno注解的方法调用。
  2. //如我们有一个方法add(MyParam param)接收一个MyParam类型的参数,而MyParam这个类是拥有注解MyAnno的,则它可以被Pointcut表达式匹配上
  3. @Pointcut("@args(com.lasse.anno.MyAnno)")
  4. public void pointCut() {
  5. }

8、@within:

@within用于匹配被代理的目标对象对应的类型或其父类型拥有指定的注解的情况,但只有在调用拥有指定注解的类上的方法时才匹配。

“@within(com.fsx.run.anno.MyAnno)”匹配被调用的方法声明的类上拥有MyAnno注解的情况。比如有一个ClassA上使用了注解MyAnno标注,并且定义了一个方法a(),那么在调用ClassA.a()方法时将匹配该Pointcut;如果有一个ClassB上没有MyAnno注解,但是它继承自ClassA,同时它上面定义了一个方法b(),那么在调用ClassB().b()方法时不会匹配该Pointcut,但是在调用ClassB().a()时将匹配该方法调用,因为a()是定义在父类型ClassA上的,且ClassA上使用了MyAnno注解。但是如果子类ClassB覆写了父类ClassA的a()方法,则调用ClassB.a()方法时也不匹配该Pointcut。

9、@annotation:

使用得也比较多

@annotation用于匹配方法上拥有指定注解的情况。

  1. // 可以匹配所有方法上标有此注解的方法
  2. @Pointcut("@annotation(com.lasse.anno.MyAnno)")
  3. public void pointCut() {
  4. }
  5. //或者:非常方便的获取到方法上面的注解
  6. @Before("@annotation(myAnno)")
  7. public void doBefore(JoinPoint joinPoint, MyAnno myAnno) {
  8. System.out.println(myAnno); //@com.lasse.anno.MyAnno()
  9. System.out.println("AOP Before Advice...");
  10. }

10、reference pointcut:

切入点引用(使用得非常多)

  1. @Aspect
  2. public class HelloAspect {
  3. @Pointcut("execution(* com.lasse.service.*.*(..)) ")
  4. public void point() {
  5. }
  6. // 这个就是一个`reference pointcut` 甚至还可以这样 @Before("point1() && point2()")
  7. @Before("point()")
  8. public void before() {
  9. System.out.println("this is from HelloAspect#before...");
  10. }
  11. }

11、bean:

这是Spring增加的一种方法,spring独有

bean用于匹配当调用的是指定的Spring的某个bean的方法时。
1、“bean(abc)”匹配Spring Bean容器中id或name为abc的bean的方法调用。
2、“bean(user*)”匹配所有id或name为以user开头的bean的方法调用。
 

  1. // 这个就能切入到AServiceImpl类的所有的外部调用的方法里
  2. @Pointcut("bean(AServiceImpl)")
  3. public void pointCut() {
  4. }

四、类型匹配语法

1、*:匹配任何数量字符;
2、…:匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数。
3、+:匹配指定类型的子类型;仅能作为后缀放在类型模式后边。

五、表达式的组合

表达式的组合其实就是对应的表达式的逻辑运算,与、或、非。可以通过它们把多个表达式组合在一起。
1、“bean(userService) && args()”匹配id或name为userService的bean的所有无参方法。
2、“bean(userService) || @annotation(MyAnnotation)”匹配id或name为userService的bean的方法调用,或者是方法上使用了MyAnnotation注解的方法调用。
3、“bean(userService) && !args()”匹配id或name为userService的bean的所有有参方法调用。

posted @ 2023-01-20 09:52  迷糊桃  阅读(1123)  评论(0编辑  收藏  举报