Spring AOP表达式速查手册

📍 切入点表达式常见形式速查手册


🎯 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
要组合 → 用逻辑运算符

记住:切入点越精确,性能越好,维护越容易!

相关推荐
PineappleCoder2 小时前
没 CDN = 用户等半天?四大核心机制:就近、分流、提速、容错全搞定
前端·性能优化
DsirNg2 小时前
JavaScript 事件循环机制详解及项目中的应用
开发语言·javascript·ecmascript
suoyue_zhan2 小时前
GBase 8s V8.8 安装部署实践指南
前端·数据库·chrome
LisEcho2 小时前
yoyoj-rn — RN 的脚手架工具可以不是 @react-native-community/cli
前端·react native·npm
如果你好2 小时前
一文搞懂 JavaScript 原型链:从本质到实战应用
前端·javascript
Tzarevich2 小时前
从命令式到声明式:用 Vue 3 构建任务清单的开发哲学
javascript·vue.js·响应式编程
醉风塘2 小时前
NPM:从“模块之痛”到“生态之基”的演化史
前端·npm·node.js
Mapmost2 小时前
【高斯泼溅】大场景可视化的「速度与激情」:Mapmost 3DGS实时渲染技术拆解
前端
研☆香2 小时前
深入解析JavaScript的arguments对象
开发语言·前端·javascript