Spring AOP切点表达式的关键词梳理

切点表达式用于定义 **AOP 通知(Advice)在哪些连接点(Join Point)上生效,**Spring AOP 基于 AspectJ 的切点表达式语法。本文梳理了切点表达式(Pointcut Expression)常见的关键词。

AspectJ用法可以参考该文:https://blog.csdn.net/taotiezhengfeng/article/details/149515395

1. 切点表达式常见关键词

Spring AOP 支持以下几种切点指示符(Pointcut Designators, PCDs)

关键词 作用 示例
execution 匹配方法执行的连接点(最常用) execution(* com.example.service.*.*(..))
@annotation 匹配带有指定注解的方法 @annotation(org.springframework.transaction.annotation.Transactional)
within 匹配指定类型内的所有方法(类级别) within(com.example.service.*)
args 匹配参数类型符合指定条件的方法 args(java.lang.String, ..) → 第一个参数是 String
@within 匹配类上带有指定注解的所有方法 @within(org.springframework.stereotype.Service)
@args 匹配参数类型上带有指定注解的方法 @args(com.example.annotation.Validated)
this 匹配代理对象是某类型的实例的方法 this(com.example.service.UserService)
target 匹配目标对象是某类型的实例的方法 target(com.example.service.UserService)
bean(Spring 特有) 匹配Spring 容器中指定 bean 名称的方法 bean(userService)bean(*Service)

2. 常见用法详解

2.1. execution(最核心)

语法:

复制代码
execution([修饰符] 返回类型 包.类.方法(参数))
  • *:通配符(任意)
  • ..:任意数量参数(包括0个)
  • +:表示当前类及其子类(如 List+ 匹配 List 及其子类)

✅ 示例:

java 复制代码
// 所有 public 方法
execution(public * *(..))

// service 包下所有类的所有方法
execution(* com.example.service.*.*(..))

// UserService 中以 save 开头的方法
execution(* com.example.service.UserService.save*(..))

// 返回 User 类型且参数为 Long 的方法
execution(com.example.model.User *(java.lang.Long))

2.2. @annotation

语法:

java 复制代码
@annotation(完整注解类名)
  • 仅匹配方法上有该注解的情况。
  • 常用于自定义注解实现权限控制、日志、缓存等。

✅ 示例:

java 复制代码
// 方法上有 @Loggable 注解
@annotation(com.example.annotation.Loggable)

// 方法上有 Spring 的 @Transactional
@annotation(org.springframework.transaction.annotation.Transactional)

⚠️ 注意:只匹配方法上的注解 ,不匹配类上的注解(类上用 @within)。

2.3. within

语法:

java 复制代码
within(类型模式)
  • 类/包范围匹配,不关心具体方法。
  • 支持通配符:*(单层)、..(多层)

✅ 示例:

java 复制代码
// UserService 类中的所有方法
within(com.example.service.UserService)

// service 包下所有类(不含子包)
within(com.example.service.*)

// service 及其子包下所有类
within(com.example.service..*)

// 所有以 Service 结尾的类
within(*..*Service)

💡 适用于按模块/层统一织入逻辑(如所有 Controller 统一加日志)。

2.4. args

语法:

java 复制代码
args(参数类型模式)
  • 匹配方法参数类型符合指定条件的方法
  • 可结合通配符使用:
    • 参数数量和类型必须匹配
    • .. 表示任意数量后续参数

✅ 示例:

java 复制代码
// 第一个参数是 String,其余任意
args(String, ..)

// 两个参数,都是 Serializable
args(java.io.Serializable, java.io.Serializable)

// 无参方法
args()

⚠️ 注意:匹配的是运行时参数的实际类型 ,不是声明类型(与 execution 不同)。

2.5. @within

语法:目标类上有指定注解,则该类中所有方法都匹配。

✅ 示例:

java 复制代码
// 所有被 @Service 注解的类中的方法
@within(org.springframework.stereotype.Service)

// 自定义模块注解
@within(com.example.annotation.ModuleA)

✅ 与 @annotation 对比:

  • @annotation → 方法上有注解
  • @within → 类上有注解

2.6. @args

语法:匹配参数类型上带有注解的方法。

✅ 示例:

java 复制代码
// 参数类型上带有 @Validated 注解
@args(com.example.annotation.Validated)

🧩 使用较少,需配合自定义注解在类级别使用。

2.7. thistarget

关键词 含义
this(Type) 代理对象是 Type 类型(Spring 代理可能是 JDK 动态代理或 CGLIB)
target(Type) 目标对象(被代理的真实对象)是 Type 类型

✅ 示例:

java 复制代码
// 代理对象实现了 UserService 接口
this(com.example.service.UserService)

// 目标对象是 UserServiceImpl 类
target(com.example.service.UserServiceImpl)

💡 在大多数 Spring 应用中,建议优先使用 executionwithin,避免因代理类型不同导致匹配失败。

2.8. bean --- Spring 特有!

语法:匹配 Spring 容器中指定名称的 Bean 的方法

  • 非 AspectJ 原生支持,是 Spring AOP 扩展。
  • 按 Spring Bean 名称匹配。

✅ 示例:

java 复制代码
// 名为 "userService" 的 Bean
bean(userService)

// 所有以 Dao 结尾的 Bean
bean(*Dao)

// user* 开头的 Bean
bean(user*)

⚠️ 注意:这是 Spring AOP 扩展,AspectJ 原生不支持。

3. 组合使用

3.1 逻辑运算符

Spring AOP 支持以下逻辑操作符:

运算符 含义
&& 与(and)
|| 或 (or)
! 非(not)

3.2 组合示例:

场景 1:带注解的 public 方法

java 复制代码
// 只拦截被 @Audit 标记的 public 方法。
@Before("@annotation(com.example.annotation.Audit) && execution(public * *(..))")

场景 2:Service 层或带事务的方法

java 复制代码
// 拦截所有 service 包方法,或任何地方带 @Transactional 的方法。
@Around("within(com.example.service..*) || @annotation(org.springframework.transaction.annotation.Transactional)")

场景 3:排除某些方法

java 复制代码
// 拦截 service 所有方法,但排除 toString()。
@Before("execution(* com.example.service.*.*(..)) && !execution(* *.toString())")

场景 4:特定参数 + 特定 Bean

java 复制代码
//userService Bean 中,参数为 String 的方法。
@Before("args(String) && bean(userService)")

4. 最佳实践建议

  1. 优先使用 execution:性能最好,语义清晰。
  2. 避免过度宽泛匹配 :如 execution(* *(..)) 会匹配所有方法,影响性能。
  3. 注解驱动更灵活 :用 @annotation 实现可插拔的 AOP 逻辑(如自定义权限、日志注解)。
  4. 组合时注意短路:将更具体的条件放前面,提高匹配效率。
  5. 测试切点 :可通过打印 JoinPoint 信息验证是否命中预期方法。
  6. 重点掌握 execution@annotationwithinargsbean 这几个关键词,就能覆盖 90% 以上的 Spring AOP 场景。

5. 相关文档

相关推荐
无限大64 小时前
验证码对抗史
后端
ZouZou老师5 小时前
C++设计模式之适配器模式:以家具生产为例
java·设计模式·适配器模式
用户2190326527355 小时前
Java后端必须的Docker 部署 Redis 集群完整指南
linux·后端
曼巴UE55 小时前
UE5 C++ 动态多播
java·开发语言
VX:Fegn08955 小时前
计算机毕业设计|基于springboot + vue音乐管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·课程设计
程序员鱼皮5 小时前
刚刚,IDEA 免费版发布!终于不用破解了
java·程序员·jetbrains
bcbnb5 小时前
苹果手机iOS应用管理全指南与隐藏功能详解
后端
用户47949283569155 小时前
面试官:DNS 解析过程你能说清吗?DNS 解析全流程深度剖析
前端·后端·面试