在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
。