题目
Spring AOP中@Around与@AfterReturning通知的区别及使用场景分析
信息
- 类型:问答
- 难度:⭐⭐
考点
AOP通知类型理解,通知执行时机控制,异常处理机制,实际场景应用
快速回答
核心区别与选择建议:
- @Around:完全控制目标方法执行,需手动调用
ProceedingJoinPoint.proceed(),可修改参数/返回值/处理异常 - @AfterReturning:仅在方法成功返回后执行,无法修改参数,但可读取返回值
- 使用场景:
- 需要方法执行控制/性能监控/事务管理 → @Around
- 只需在成功返回后记录日志/发送通知 → @AfterReturning
一、核心原理对比
执行流程示意图:
@Around [before] → 目标方法执行 → @Around [after] → @AfterReturning- @Around:
- 通过
ProceedingJoinPoint控制目标方法执行时机 - 可捕获并处理所有异常(包括未捕获异常)
- 返回值类型为
Object,可修改原始返回值
- 通过
- @AfterReturning:
- 通过
returning属性绑定返回值(只读) - 若方法抛出异常,则不会触发该通知
- 无法修改方法参数或返回值
- 通过
二、代码示例对比
1. @Around 实现方法耗时监控:
@Around("execution(* com.example.service.*.*(..))")
public Object logExecutionTime(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
Object result = pjp.proceed(); // 必须显式调用
long duration = System.currentTimeMillis() - start;
// 可修改返回值
if (result instanceof String) {
result = ((String) result).toUpperCase();
}
logger.info("方法 {} 执行耗时: {}ms", pjp.getSignature(), duration);
return result;
}2. @AfterReturning 实现成功操作日志:
@AfterReturning(
pointcut = "execution(* com.example.service.UserService.createUser(..))",
returning = "userId" // 绑定返回值
)
public void logUserCreation(Long userId) {
// 只能读取返回值,无法修改
auditLogService.log("用户ID: " + userId + " 创建成功");
}三、最佳实践与场景选择
| 通知类型 | 适用场景 | 不适用场景 |
|---|---|---|
| @Around |
|
|
| @AfterReturning |
|
|
四、常见错误
- 错误1:在@Around中忘记调用
proceed()导致目标方法未执行// 错误示例:缺少proceed调用
@Around(...)
public void wrongAdvice(ProceedingJoinPoint pjp) {
logger.info("方法被拦截");
// 丢失pjp.proceed()调用
} - 错误2:尝试在@AfterReturning中修改返回值
// 无效操作:返回值修改不会生效
@AfterReturning(returning = "result", pointcut = ...)
public void afterReturning(Object result) {
result = "modified"; // 修改无效!
} - 错误3:混淆异常处理机制
- @AfterReturning在方法抛出异常时不会触发
- 需配合@AfterThrowing实现完整异常处理
五、扩展知识
- 执行顺序控制:多个通知可通过
@Order注解指定顺序 - 性能考量:@Around比@AfterReturning更重,非必要不滥用
- 组合使用案例:
@Around("serviceLayer()") // 负责事务管理
@AfterReturning("serviceLayer()") // 负责成功日志
@AfterThrowing("serviceLayer()") // 负责异常日志
public void fullAspectSetup() { ... }