在 Spring AOP 中,当**前置通知(@Before)、环绕通知(@Around)、后置通知(@AfterReturning)**同时作用于同一个方法时,它们的执行顺序遵循明确的规则。以下是完整的执行流程和优先级说明:
1. 标准执行顺序
当所有通知同时存在时,完整的执行链条如下:
1. 环绕通知(@Around)的前半部分
→ 2. 前置通知(@Before)
→ 3. 目标方法执行
→ 4. 环绕通知(@Around)的后半部分
→ 5. 后置通知(@AfterReturning)
图示流程
2. 关键细节说明
(1) 环绕通知(@Around)是主导者
- 只有调用
ProceedingJoinPoint.proceed()
时,才会触发后续通知和目标方法。 - 如果环绕通知中不调用
proceed()
,则整个链条终止(目标方法和其他通知都不会执行)。
(2) 异常情况下的行为
- 如果目标方法或通知抛出异常:
- 后置通知(@AfterReturning)不会执行
- 环绕通知的后续代码也不会执行
- 但
@After
(最终通知)仍会执行(如果有)
(3) 多个同类型通知的执行顺序
如果存在多个同类型通知(如多个 @Around
),其顺序由 @Order
注解或 Ordered
接口控制,数值越小优先级越高。
3. 代码示例验证
定义切面
@Aspect
@Component
public class MyAspect {
@Before("execution(* com.example.service.*.*(..))")
public void beforeAdvice() {
System.out.println("[前置通知] @Before");
}
@Around("execution(* com.example.service.*.*(..))")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("[环绕通知] @Around - 前");
Object result = pjp.proceed(); // 触发目标方法和其他通知
System.out.println("[环绕通知] @Around - 后");
return result;
}
@AfterReturning("execution(* com.example.service.*.*(..))")
public void afterReturningAdvice() {
System.out.println("[后置通知] @AfterReturning");
}
}
执行输出
当目标方法被调用时,控制台输出:
[环绕通知] @Around - 前
[前置通知] @Before
[目标方法执行]
[环绕通知] @Around - 后
[后置通知] @AfterReturning
4. 与其他通知的完整顺序
如果加入 最终通知(@After) 和 异常通知(@AfterThrowing),完整顺序为:
@Around
前半@Before
- 目标方法
- 成功:
4.@AfterReturning
5.@Around
后半
6.@After
(最终通知) - 失败(抛出异常):
4.@AfterThrowing
5.@After
(最终通知)
- 成功:
5. 设计建议
- 控制流:通过环绕通知可以完全控制目标方法是否执行。
- 性能敏感:避免在环绕通知中添加耗时逻辑,因其在调用链的最外层。
- 事务管理:Spring 的事务通知(
@Transactional
)本质是环绕通知,优先级通常最高。
理解这一执行顺序对调试复杂 AOP 场景至关重要,尤其是在需要多个通知协同工作时。