Spring AOP 注解使用案例与场景设计
目录
一、五大核心注解对比
| 注解 | 执行时机 | 使用场景 |
|---|---|---|
| @Before | 方法执行前 | 参数校验、权限检查、日志记录 |
| @AfterReturning | 方法正常返回后 | 处理返回值、缓存更新 |
| @AfterThrowing | 方法抛出异常后 | 异常日志、告警通知 |
| @After | 方法结束后(finally) | 资源释放、清理工作 |
| @Around | 环绕方法 | 性能监控、事务控制、缓存 |
二、注解使用案例
2.1 @Before - 参数校验
1 |
|
常用场景:接口入参校验、权限验证、限流检查
2.2 @AfterReturning - 缓存更新
1 |
|
常用场景:数据库更新后刷新缓存、发送通知消息
2.3 @AfterThrowing - 异常告警
1 |
|
常用场景:统一异常处理、告警通知、故障记录
2.4 @After - 资源清理
1 |
|
常用场景:资源释放、清理临时文件、重置上下文
2.5 @Around - 性能监控(最常用)
1 |
|
常用场景:性能监控、事务控制、熔断降级
三、实际场景设计
3.1 场景1:操作日志记录(企业级)
1 |
|
3.2 场景2:接口幂等性控制
1 |
|
3.3 场景3:接口限流
1 |
|
3.4 场景4:重试机制
1 |
|
四、切点表达式汇总
1 | // 1. 精确匹配 |
切点表达式说明
| 表达式 | 说明 |
|---|---|
execution(* com.example.service.*.*(..)) |
匹配 service 包下所有类的所有方法 |
execution(public * com.example..*.*(..)) |
匹配 public 方法 |
@annotation(com.example.Log) |
匹配带 @Log 注解的方法 |
@within(org.springframework.stereotype.Service) |
匹配 Service 类下的所有方法 |
this(com.example.Service) |
匹配实现了 Service 接口的代理对象 |
target(com.example.Service) |
匹配实现了 Service 接口的目标对象 |
五、最佳实践建议
5.1 注解选择建议
| 建议 | 说明 |
|---|---|
| 优先使用 @Around | 功能最强大,可以控制入参、返回值、异常 |
| 避免 @Around 包裹业务逻辑 | 用于横切关注点,不要改变业务流程 |
| ThreadLocal 必须清理 | 防止内存泄漏 |
| 异常处理要谨慎 | 不要吞掉异常,做好日志记录 |
| 性能敏感代码慎用 AOP | AOP 有性能开销,高频方法注意测试 |
| 组合使用注解 | @Before + @AfterReturning 比 @Around 更清晰 |
5.2 性能优化
1 | // 优化前:每个方法都拦截 |
5.3 常见问题处理
问题1:@Around 不执行
1 | // 错误:private 方法不会被代理 |
问题2:同类方法调用不生效
1 |
|
5.4 实践检查清单
使用 AOP 前检查
- 是否需要修改方法参数?(是 → 使用 @Around)
- 是否需要修改返回值?(是 → 使用 @Around 或 @AfterReturning)
- 是否需要捕获异常?(是 → 使用 @Around 或 @AfterThrowing)
- 是否只是记录日志?(是 → 使用 @Before 或 @After)
- ThreadLocal 是否正确清理?
- 是否考虑了性能影响?
5.5 推荐组合方案
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 参数校验 | @Before | 简单直接,不修改业务逻辑 |
| 缓存更新 | @AfterReturning | 只在成功时更新缓存 |
| 性能监控 | @Around | 可以统计完整耗时 |
| 异常处理 | @AfterThrowing | 专注异常场景 |
| 完整日志 | @Around | 可以记录入参和返回值 |
| 幂等控制 | @Around | 需要控制是否执行 |
延伸阅读
- ^^Spring官方文档 - AOP概念^^
- ^^Spring AOP API文档^^
- ^^AspectJ编程指南^^
- ^^Spring AOP与AspectJ区别^^