侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

Spring AOP中@Around与@AfterReturning通知的区别及使用场景分析

2025-12-12 / 0 评论 / 4 阅读

题目

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() { ... }