Spring AOP Pointcut 表达式的语法是怎样的?(execution(...) 是最常用的,还有哪些

Pointcut 表达式是 AOP 的核心,我将详细解析最常用的 execution 表达式,并介绍其他几种同样非常有用的表达式。

1. execution 指示符 (最常用,最强大)

execution 用于匹配方法的执行(Join Point)。它的语法结构最为完整,也最为灵活。

语法结构
execution( [修饰符模式]? 返回类型模式 [声明类型模式]? 方法名模式(参数模式) [抛出异常模式]? )
  • 方括号 [] 内的部分是可选的。
  • ? 表示该部分是可选的。
语法分解与示例

让我们通过一个具体的例子来逐一分解:
execution(public * com.example.service..*.set*(..))

部分示例含义
[修饰符模式]public匹配 public 修饰的方法。可以省略,表示匹配任何修饰符。也可以用 *
返回类型模式*匹配任意返回类型。也可以是具体的类型如 Stringvoid
[声明类型模式]com.example.service..*.匹配方法所在的类型。这部分非常灵活:
- com.example.service.UserService:精确匹配 UserService 类。
- com.example.service.*:匹配 service 包下的任意直接类
- com.example.service..*:匹配 service及其所有子包下的任意类。最后的 . 是必需的。
方法名模式set*匹配以 set 开头的方法名。也可以是精确的方法名 setName 或通配符 *
(参数模式)(..)匹配任意数量、任意类型的参数。这是最常用的模式。
- ():匹配无参方法。
- (*):匹配只有一个任意类型参数的方法。
- (String, ..):匹配第一个参数是 String,后面有任意数量、任意类型的参数。
[抛出异常模式](省略)匹配方法声明抛出的异常类型。例如 throws java.io.IOException。这部分很少使用。

这个例子的完整含义是:
拦截 com.example.service 包及其所有子包中,所有类的,所有以 set 开头的,public 修饰的,不限返回值和参数的方法。


2. 其他常用 Pointcut 指示符

除了 execution,还有一些在特定场景下非常好用的指示符。

within 指示符

within 用于限定连接点必须在指定的类型或包的范围内。它比 execution 更粗粒度,只关心位置,不关心方法签名。

  • 语法: within(类型或包模式)

  • 示例:

    • within(com.example.service.UserService): 匹配 UserService 类中的所有方法
    • within(com.example.service.*): 匹配 service 包下所有类中的所有方法。
    • within(com.example.service..*): 匹配 service 包及其所有子包下所有类中的所有方法。
  • execution 的区别:

    • execution(* com.example.service.UserService.*(..))within(com.example.service.UserService) 看起来相似,但 within 的粒度更大。例如,within 不关心方法的修饰符、返回类型等。
@annotation 指示符

@annotation 用于匹配持有指定注解的方法。这对于创建自定义注解来实现 AOP 非常有用,是实现声明式功能(如声明式日志、声明式缓存)的最佳方式。

  • 语法: @annotation(注解类型的完全限定名)

  • 示例:

    1. 定义一个自定义注解:
      @Target(ElementType.METHOD)
      @Retention(RetentionPolicy.RUNTIME)
      public @interface MyLoggable {}
      
    2. 在方法上使用注解:
      @Service
      public class MyService {
          @MyLoggable
          public void doSomething() { /* ... */ }
      }
      
    3. 编写切点:
      @Pointcut("@annotation(com.example.aop.MyLoggable)")
      public void loggableMethods() {}
      
      这个切点会精确地匹配所有被 @MyLoggable 注解的方法。
@within@target
  • @within: 匹配持有指定注解的类中的所有方法。

    • 示例: @within(org.springframework.stereotype.Service) 会匹配所有被 @Service 注解的类中的所有方法。
  • @target: 匹配目标对象的类持有指定注解的所有方法。@within@target 在大多数情况下效果相同。

args@args

这两个指示符用于根据方法的参数来匹配。

  • args(): 匹配方法的参数类型

    • args(java.lang.String, ..): 匹配第一个参数是 String 类型的方法。
    • args(): 匹配无参方法。
    • args(user): 这种形式不仅匹配参数类型,还能在通知中绑定参数值
      @Before("execution(* com.example..*.*(com.example.User)) && args(user)")
      public void processUser(User user) {
          //可以直接使用 user 对象
          System.out.println("Processing user: " + user.getName());
      }
      
  • @args(): 匹配方法的参数在运行时所持有的注解

    • @args(com.example.validation.Validatable, ..): 匹配第一个参数对象被 @Validatable 注解标注的方法。

3. 组合切点 (Combining Pointcuts)

你可以使用逻辑运算符 && (与), || (或), ! (非) 来组合多个切点,创建更复杂的规则。

@Aspect
@Component
public class SecurityAspect {

    // 匹配 service 包下的所有方法
    @Pointcut("within(com.example.service..*)")
    public void inServiceLayer() {}

    // 匹配被 @AdminOnly 注解的方法
    @Pointcut("@annotation(com.example.security.AdminOnly)")
    public void adminOnlyMethods() {}

    // 组合切点:在 service 层中,并且是 admin-only 的方法
    @Before("inServiceLayer() && adminOnlyMethods()")
    public void checkAdminAccess() {
        // ... 执行权限检查逻辑
        System.out.println("Admin access granted!");
    }

    // 组合切点:不在 service 层中的所有方法
    @Before("!inServiceLayer()")
    public void nonServiceMethodLog() {
        // ...
    }
}

总结

指示符作用优点
execution最核心、最常用,匹配方法的完整签名。最精确,控制粒度最细。
within匹配指定包或类中的所有方法。语法简单,适合按模块划分。
@annotation匹配持有指定注解的方法解耦性最好,通过注解驱动AOP,业务代码无侵入。
@within, @target匹配持有指定注解的类中的所有方法。适合对整个类别的Bean进行增强。
args, @args根据方法的参数类型或参数注解来匹配。适合处理特定类型的数据流。
**&&, `, !`**

在实际开发中,execution@annotation 是使用频率最高的两种方式。建议优先使用 @annotation 来实现自定义的声明式功能,因为它能让我们的代码意图更加清晰。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰糖心书房

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值