在AspectJ或Spring AOP中,@Around、@Before 和 @After 是常用的通知(Advice)注解,它们的执行时机和用途不同。以下是它们的详细说明和对比:
1. @Around
执行时机:
@Around 通知包裹目标方法的执行,可以在方法调用前、后插入逻辑,甚至完全控制是否执行目标方法。
- 触发条件:当目标方法被调用时,
@Around会最先执行。 - 控制权:通过
ProceedingJoinPoint.proceed()决定是否继续执行目标方法:- 调用
proceed()会执行目标方法,可以在其前后添加逻辑。 - 如果不调用
proceed(),目标方法不会执行。
- 调用
- 适用场景:需要完全控制目标方法的执行(如性能监控、事务管理、重试机制)。
示例:
@Around("execution(* com.example.service.*.*(..))")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {// 目标方法执行前的逻辑System.out.println("Before method execution");// 执行目标方法(可控制是否执行)Object result = joinPoint.proceed();// 目标方法执行后的逻辑System.out.println("After method execution");return result;
}
2. @Before
执行时机:
@Before 通知在目标方法执行之前触发,无法阻止方法执行(除非抛出异常)。
- 触发条件:目标方法被调用时,在
@Around之后、目标方法之前执行。 - 适用场景:预处理逻辑(如参数校验、日志记录、权限检查)。
示例:
@Before("execution(* com.example.service.*.*(..))")
public void beforeAdvice() {System.out.println("Before method: 执行前逻辑");
}
3. @After
执行时机:
@After 通知在目标方法执行结束后触发,无论方法是否成功完成或抛出异常(类似于 finally 块)。
- 触发条件:目标方法执行完毕(无论正常返回还是异常退出)。
- 适用场景:清理资源、记录方法结束日志。
示例:
@After("execution(* com.example.service.*.*(..))")
public void afterAdvice() {System.out.println("After method: 清理资源或记录日志");
}
执行顺序对比
当一个方法被 @Around、@Before、@After 同时拦截时,执行顺序如下:
@Around的前半部分 →@Before→- 目标方法执行 →
@Around的后半部分(在proceed()之后) →@After(无论成功或异常)
示意图:
@Around 开始@Before 执行目标方法执行
@Around 结束
@After 执行
关键区别
| 注解 | 控制目标方法执行 | 能否修改返回值 | 是否处理异常 |
|---|---|---|---|
@Around | 是(通过 proceed()) | 是 | 是(可捕获并处理异常) |
@Before | 否 | 否 | 否(抛出异常会阻止方法执行) |
@After | 否 | 否 | 否(在方法结束后执行) |
其他相关注解
@AfterReturning:仅在目标方法成功返回后执行。@AfterThrowing:仅在目标方法抛出异常后执行。
总结
@Around:最灵活,适合需要完全控制方法执行的场景。@Before/@After:适合简单的预处理或后处理,无需控制方法执行流程。- 执行顺序:
@Around→@Before→ 目标方法 →@Around→@After。
