切点表达式用于定义 **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. this 与 target
| 关键词 | 含义 |
|---|---|
this(Type) |
代理对象是 Type 类型(Spring 代理可能是 JDK 动态代理或 CGLIB) |
target(Type) |
目标对象(被代理的真实对象)是 Type 类型 |
✅ 示例:
java
// 代理对象实现了 UserService 接口
this(com.example.service.UserService)
// 目标对象是 UserServiceImpl 类
target(com.example.service.UserServiceImpl)
💡 在大多数 Spring 应用中,建议优先使用
execution或within,避免因代理类型不同导致匹配失败。
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. 最佳实践建议
- 优先使用
execution:性能最好,语义清晰。 - 避免过度宽泛匹配 :如
execution(* *(..))会匹配所有方法,影响性能。 - 注解驱动更灵活 :用
@annotation实现可插拔的 AOP 逻辑(如自定义权限、日志注解)。 - 组合时注意短路:将更具体的条件放前面,提高匹配效率。
- 测试切点 :可通过打印
JoinPoint信息验证是否命中预期方法。 - 重点掌握
execution、@annotation、within、args和bean这几个关键词,就能覆盖 90% 以上的 Spring AOP 场景。