📍 切入点表达式常见形式速查手册
🎯 execution(最常用)
语法模板
java
execution(修饰符? 返回类型 包名.类名.方法名(参数) 异常?)
可以使用通配符描述切入点
- " * " :单个独立的任意符号,可以通配任意返回值、包名、类名、方法名、任意类型的一个参数,也可以通配包、类、方法名的一部分
- ... :多个连续的任意符号,可以通配任意层级的包,或任意类型、任意个数的参数
常用形式
1. 按包匹配
java
// 精确包匹配
execution(* com.example.service.*.*(..)) // service包下所有类的方法
execution(* com.example.service..*.*(..)) // service包及其子包下所有方法
// 多级包匹配
execution(* com..service.*.*(..)) // 任意父包下的service包
2. 按类匹配
java
// 精确类匹配
execution(* com.example.service.UserService.*(..)) // UserService所有方法
// 按类名模式匹配
execution(* com.example.service.*Service.*(..)) // 以Service结尾的类
execution(* com.example.service.*Impl.*(..)) // 以Impl结尾的类
3. 按方法名匹配
java
// 精确方法名
execution(* com.example.service.UserService.save(..)) // 特定方法
// 模式匹配方法名
execution(* com.example.service.*.save*(..)) // 以save开头的方法
execution(* com.example.service.*.*User(..)) // 以User结尾的方法
execution(* com.example.service.*.get*()) // 无参的getter方法
execution(* com.example.service.*.set*(*)) // 单个参数的setter方法
4. 按参数匹配
java
// 精确参数
execution(* com.example.service.*.*(String, int)) // 参数为(String, int)
// 参数模式
execution(* com.example.service.*.*(*)) // 单个任意参数
execution(* com.example.service.*.*(*, *)) // 两个任意参数
execution(* com.example.service.*.*(*, String)) // 第二个参数为String
execution(* com.example.service.*.*(.., String)) // 最后一个参数为String
execution(* com.example.service.*.*(java.lang.String)) // 明确指定类型
execution(* com.example.service.*.*(com.example.User)) // 自定义类型参数
5. 按返回类型匹配
java
execution(void com.example.service.*.*(..)) // 返回void的方法
execution(String com.example.service.*.*(..)) // 返回String的方法
execution(List<*> com.example.service.*.*(..)) // 返回List的方法
execution(* com.example.service.*.*(..)) // 任意返回值
🏷️ @annotation(基于注解)
形式
java
// 匹配方法上的注解
@annotation(org.springframework.transaction.annotation.Transactional)
@annotation(com.example.annotation.Log)
@annotation(com.example.annotation.Cacheable)
// 组合使用
@annotation(com.example.annotation.Log) &&
execution(* com.example.service.*.*(..))
示例注解
java
// 自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
String value() default "";
}
// 使用
@Log("用户操作")
public void saveUser() { ... }
📦 within(按类型)
形式
java
// 精确类
within(com.example.service.UserService) // UserService所有方法
// 包级别
within(com.example.service.*) // service包下所有类
within(com.example.service..*) // service包及其子包下所有类
// 接口/实现类
within(com.example.service.BaseService+) // BaseService及其实现类
🏢 @within(按类上的注解)
形式
java
// 匹配类上有特定注解的所有方法
@within(org.springframework.stereotype.Service) // 所有@Service类
@within(org.springframework.web.bind.annotation.RestController) // 所有@RestController类
@within(com.example.annotation.Secured) // 所有@Secured注解类
🧾 bean(Spring特有)
形式
java
// 按Bean名称
bean(userService) // 名为userService的Bean
bean(*Service) // 以Service结尾的Bean
bean(user*) // 以user开头的Bean
bean(*Controller) // 以Controller结尾的Bean
bean(*ServiceImpl) // 以ServiceImpl结尾的Bean
🔗 args(按参数类型/注解)
形式
java
// 按参数类型
args(java.lang.String) // 第一个参数是String
args(java.lang.String, java.lang.Long) // 第一个String,第二个Long
args(com.example.User, ..) // 第一个参数是User,后面任意
// 按参数注解
@args(javax.validation.Valid) // 参数有@Valid注解
@args(com.example.annotation.NotEmpty) // 参数有@NotEmpty注解
🔄 this/target(按代理/目标类型)
形式
java
// JDK代理
this(com.example.service.UserService) // 代理对象是UserService类型
target(com.example.service.UserService) // 目标对象是UserService类型
// CGLIB代理(两者相同)
this(com.example.service.UserServiceImpl)
target(com.example.service.UserServiceImpl)
⚡ 组合表达式
逻辑运算符
java
// AND (&&)
execution(* com.example.service.*.*(..)) && within(com.example.service.*)
execution(* com.example.service.*.*(..)) && @annotation(org.springframework.transaction.annotation.Transactional)
// OR (||)
execution(* com.example.service.*.save*(..)) || execution(* com.example.service.*.update*(..))
@annotation(com.example.annotation.Log) || @annotation(com.example.annotation.Monitor)
// NOT (!)
execution(* com.example.service.*.*(..)) && !execution(* com.example.service.*.get*(..))
within(com.example.controller.*) && !@annotation(com.example.annotation.SkipAuth)
实际组合示例
java
// 1. 监控Service层非查询方法
@Pointcut("within(@org.springframework.stereotype.Service *) && " +
"execution(* *.*(..)) && " +
"!execution(* *.get*(..)) && " +
"!execution(* *.find*(..)) && " +
"!execution(* *.select*(..))")
public void serviceWriteOperation() {}
// 2. 权限控制:Controller层需要鉴权的方法
@Pointcut("within(@org.springframework.web.bind.annotation.RestController *) && " +
"(@annotation(org.springframework.web.bind.annotation.PostMapping) || " +
" @annotation(org.springframework.web.bind.annotation.PutMapping) || " +
" @annotation(org.springframework.web.bind.annotation.DeleteMapping))")
public void needAuthOperation() {}
// 3. 数据库操作监控
@Pointcut("execution(* com.example.repository.*.*(..)) || " +
"execution(* com.example.dao.*.*(..))")
public void databaseOperation() {}
// 4. 排除特定方法
@Pointcut("within(com.example.service.*) && " +
"!execution(* com.example.service.HealthCheckService.*(..))")
public void serviceExcludeHealthCheck() {}
📝 命名切入点(可复用)
定义
java
@Aspect
@Component
public class SystemArchitecture {
// 1. 分层架构
@Pointcut("within(@org.springframework.stereotype.Service *)")
public void serviceLayer() {}
@Pointcut("within(@org.springframework.web.bind.annotation.RestController *)")
public void controllerLayer() {}
@Pointcut("within(@org.springframework.stereotype.Repository *)")
public void repositoryLayer() {}
// 2. 注解定义
@Pointcut("@annotation(com.example.annotation.Log)")
public void loggable() {}
@Pointcut("@annotation(com.example.annotation.Cacheable)")
public void cacheable() {}
@Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)")
public void transactional() {}
// 3. 组合定义
@Pointcut("serviceLayer() && loggable()")
public void loggableService() {}
@Pointcut("controllerLayer() && transactional()")
public void transactionalController() {}
}
// 在其他切面中使用
@Before("SystemArchitecture.serviceLayer()")
public void beforeService() { ... }
📊 实际开发常用形式总结
| 场景 | 推荐形式 | 示例 |
|---|---|---|
| 全局日志 | within + 注解 | within(@org.springframework.stereotype.Service *) |
| 事务管理 | @annotation | @annotation(org.springframework.transaction.annotation.Transactional) |
| 权限控制 | @annotation + execution | @annotation(com.example.annotation.RequireAuth) |
| 缓存切面 | @annotation | @annotation(com.example.annotation.Cacheable) |
| 性能监控 | execution + 排除 | execution(* com.example.service.*.*(..)) && !execution(* *.get*(..)) |
| 参数校验 | args | args(com.example.dto.*) |
| 异常处理 | within + 包名 | within(com.example.controller..*) |
| 特定Bean | bean | bean(userService) |
🎯 按优先级排序
java
// 执行顺序:从精确到宽泛
1. @annotation(com.example.CustomAnnotation) // 最精确
2. execution(* com.example.service.UserService.save(..))
3. execution(* com.example.service.UserService.*(..))
4. within(com.example.service.UserService)
5. execution(* com.example.service.*.*(..))
6. within(com.example.service.*) // 最宽泛
7. execution(* *.*(..))
⚠️ 常见错误
错误示例
java
// ❌ 过于宽泛(影响性能)
execution(* *.*(..))
// ❌ 缺少参数括号
execution(* com.example.service.*.*)
// ❌ 包路径错误
execution(* com.example.*Service.*(..)) // 包名中包含通配符
// ✅ 正确做法
execution(* com.example.service.*Service.*(..)) // 类名中包含通配符
最佳实践
java
// 1. 优先使用注解方式
@annotation(com.example.annotation.Log)
// 2. 精确匹配,避免扫描过多类
within(com.example.service..*)
// 3. 组合使用,提高可读性
@Pointcut("within(com.example.service..*) && " +
"@annotation(org.springframework.transaction.annotation.Transactional)")
public void transactionalService() {}
🔧 调试技巧
1. 查看匹配的方法
java
@Aspect
@Component
public class DebugAspect {
@Before("yourPointcut()")
public void debug(JoinPoint joinPoint) {
System.out.println("匹配方法: " +
joinPoint.getSignature().toShortString());
}
}
2. 测试切入点表达式
java
// 使用AspectJ工具测试
// 下载aspectjweaver,使用ajc编译测试
📚 速查表
✅ execution - 按方法签名匹配(最灵活)
✅ @annotation - 按方法注解匹配(最常用)
✅ within - 按类型/包匹配
✅ @within - 按类注解匹配
✅ bean - 按Spring Bean名称匹配
✅ args - 按参数类型/注解匹配
✅ this/target - 按代理/目标类型匹配
✅ 组合 - 使用&&、||、!组合多个条件
💎 一句话总结
切入点表达式选择指南:
要精确 → 用@annotation
要批量 → 用within
要灵活 → 用execution
要简单 → 用bean
要组合 → 用逻辑运算符
记住:切入点越精确,性能越好,维护越容易!