20 spring-注解驱动AOP--切入点表达式

1 概念

指的是遵循特定的语法用于捕获每一个种类的可使用连接点的语法。用于对符合语法格式的连接点进行增强。

1.1 分类

  • 方法执行:execution(MethodSignature)
  • 方法调用:call(MethodSignature)
  • 构造器执行:execution(ConstructorSignature)
  • 构造器调用:call(ConstructorSignature)
  • 类初始化:staticinitialization(TypeSignature)
  • 属性读操作:get(FieldSignature)
  • 属性写操作:set(FieldSignature)
  • 例外处理执行:handler(TypeSignature )
  • 对象初始化:initialization(ConstructorSignature)
  • 对象预先初始化:preinitialization(ConstructorSignature)

1.2 关键字

支持的AspectJ切入点指示符如下:

  • execution:用于匹配方法执行的连接点;
  • within:用于匹配指定类型内的方法执行;
  • this:用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这
    样就可能包括引入接口也类型匹配;
  • target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就
    不包括引入接口也类型匹配;
  • args:用于匹配当前执行的方法传入的参数为指定类型的执行方法;
  • @within:用于匹配所以持有指定注解类型内的方法;
  • @target:用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;
  • @args:用于匹配当前执行的方法传入的参数持有指定注解的执行;
  • @annotation:用于匹配当前执行方法持有指定注解的方法;
  • bean:Spring AOP扩展的,AspectJ没有对于指示符,用于匹配特定名称的Bean对象的
    执行方法;
  • reference pointcut:表示引用其他命名切入点,只有@ApectJ风格支持,Schema风
    格不支持。

1.3 切入点表达式的通配符

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

eg:

  1. java.lang.String 匹配String类型;
  2. java.*.String 匹配java包下的任何“一级子包”下的String类型; 如匹配java.lang.String,但不匹配java.lang.ss.String
  3. java..* 匹配java包及任何子包下的任何类型; 如匹配java.lang.Stringjava.lang.annotation.Annotation
  4. java.lang.*ing 匹配任何java.lang包下的以ing结尾的类型;
  5. java.lang.Number+ 匹配java.lang包下的任何Number的子类型; 如匹配java.lang.Integer,也匹配java.math.BigInteger

比如:

@Service
@Slf4j
public final class UserServiceImpl implements UserService {
    @Override
    public User save(User user, String id) {
        user.setId(id);
        System.out.println("模拟保存用户");
        return user;
    }
}

针对上面这个UserServiceImpl类中的save方法,下面几个切入点表达式是否会匹配到呢:

/***
  匹配的就是:
  	1. study.wyy.spring.anno.aop.service.impl这个包下及其子包所有的类
  	2. 方法名字是以save结尾的方法
  	3. 匹配任何数量的参数
  所以这个通知是可以匹配到的
***/
@Before(value = "execution(* study.wyy.spring.anno.aop.service.impl.*.*save(..))")
public void beforeLog() {
   System.out.println("[前置通知:beforeLog]: 在方法执行之前进行日志打印");
}
/***
  匹配的就是:
  	1. study.wyy.spring.anno.aop.service.impl这个包下及其子包所有的类
  	2. 方法名字是以save结尾的方法
  	3. 匹配没有入参的方法
  	所以这个通知是不会匹配到的
***/
@Before(value = "execution(* study.wyy.spring.anno.aop.service.impl.*.*save())")
public void beforeLog() {
    System.out.println("[前置通知:beforeLog]: 在方法执行之前进行日志打印");
}
/***
  匹配的就是:
  	1. study.wyy.spring.anno.aop.service.impl这个包下及其子包所有的类
  	2. 所有的方法
  	3. 匹配参数为两个,并且参数类型为study.wyy.spring.anno.aop.model.User和java.lang.String
  	所以这个通知是会匹配到的
***/
@Before(value = "execution(* study.wyy.spring.anno.aop.service.impl.*.*(study.wyy.spring.anno.aop.model.User,java.lang.String))")
public void beforeLog() {
    System.out.println("[前置通知:beforeLog]: 在方法执行之前进行日志打印");
}
/***
  匹配的就是:
  	1. study.wyy.spring.anno.aop.service.impl这个包下及其子包所有的类
  	2. 所有的方法
  	3. 匹配参数为两个,并且参数类型为study.wyy.spring.anno.aop.model.User和java.lang.Integer
  	所以这个通知是不会匹配到的
***/
@Before(value = "execution(* study.wyy.spring.anno.aop.service.impl.*.*(study.wyy.spring.anno.aop.model.User,java.lang.Integer))")
public void beforeLog() {
    System.out.println("[前置通知:beforeLog]: 在方法执行之前进行日志打印");
}
/***
  匹配的就是:
  	方法上有Deprecated注解的方法,所以也不会匹配
***/
@Before(value = "@annotation(java.lang.Deprecated)")
public void beforeLog() {
    System.out.println("[前置通知:beforeLog]: 在方法执行之前进行日志打印");
}

如果给这个方法加上这个注解就可以被匹配到:

package study.wyy.spring.anno.aop.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import study.wyy.spring.anno.aop.model.User;
import study.wyy.spring.anno.aop.service.UserService;
@Service
@Slf4j
public final class UserServiceImpl implements UserService {
    @Override
    @Deprecated
    public User save(User user, String id) {
        user.setId(id);
        System.out.println("模拟保存用户");
        return user;
    }
}
/***
  匹配的就是:
  	方法上形参是User和String类型,所以会匹配
***/
 @Before(value = "args(study.wyy.spring.anno.aop.model.User,java.lang.String)")
 public void beforeLog() {
     System.out.println("[前置通知:beforeLog]: 在方法执行之前进行日志打印");
 }
/***
  匹配的就是:
  	在容器中bean的名字是userServiceImpl的执行的方法,所以也会被匹配到
***/
 @Before(value = "bean(userServiceImpl)")
 public void beforeLog() {
     System.out.println("[前置通知:beforeLog]: 在方法执行之前进行日志打印");
 }
/***
  匹配的就是:
  	目标对象是UserService的类型,所以也会被匹配到
***/
@Before(value = "target(study.wyy.spring.anno.aop.service.UserService)")
public void beforeLog() {
    System.out.println("[前置通知:beforeLog]: 在方法执行之前进行日志打印");
}
/***
  匹配的就是:
  	目标对象标持有Controller注解,所以也不会被匹配到
***/
@Before(value = "@target(org.springframework.stereotype.Controller)")
public void beforeLog() {
   System.out.println("[前置通知:beforeLog]: 在方法执行之前进行日志打印");
}
/***
注意和target的的区别
  匹配的就是:
  	目标对象得是指定的类型
***/
//@Before(value = "within(study.wyy.spring.anno.aop.service.UserService)") 不会匹配,
@Before(value = "within(study.wyy.spring.anno.aop.service.impl.UserServiceImpl)") //会匹配
  public void beforeLog() {
      System.out.println("[前置通知:beforeLog]: 在方法执行之前进行日志打印");
}

1.4 切入点表达式的逻辑条件

还可以通过逻辑操作符,将上面的的这些多个表达式进行逻辑或(||),逻辑与(&&)的操作

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值