你的理解部分正确,但需要更精准的修正。Spring AOP 的拦截器链顺序和实际执行顺序之间存在递归推进关系,这需要结合拦截器的具体实现来理解。我们以你的代码为例详细分析:
1. 拦截器链的构造顺序
在你的代码中,@Before
和 @After
两个通知会被转换为以下拦截器,并按如下顺序加入链中:
-
MethodBeforeAdviceInterceptor
(对应@Before
) -
AspectJAfterAdvice
(对应@After
)
拦截器链的顺序是:@Before
→ @After
(注意:此时原始方法尚未执行!)。
2. 拦截器链的执行顺序(关键)
当 ReflectiveMethodInvocation.proceed()
被调用时,拦截器链的执行流程如下:
(1) 初始状态
currentInterceptorIndex = -1
- 拦截器链顺序:
[MethodBeforeAdviceInterceptor, AspectJAfterAdvice]
(2) 第一次调用 proceed()
-
currentInterceptorIndex
递增为0
(第一个拦截器:MethodBeforeAdviceInterceptor
) - 执行
MethodBeforeAdviceInterceptor.invoke(this)
:
// 伪代码:MethodBeforeAdviceInterceptor 的逻辑
public Object invoke(MethodInvocation mi) {
// 1. 先执行前置通知(@Before)
this.advice.before(...);
// 2. 继续调用 mi.proceed() → 触发下一个拦截器
return mi.proceed();
}
- 此时会打印 "AOP 前置通知",然后继续调用
mi.proceed()
。
(3) 第二次调用 proceed()
-
currentInterceptorIndex
递增为1
(第二个拦截器:AspectJAfterAdvice
) - 执行
AspectJAfterAdvice.invoke(this)
:
// 伪代码:AspectJAfterAdvice 的逻辑
public Object invoke(MethodInvocation mi) {
try {
// 1. 继续调用 mi.proceed() → 此时已无后续拦截器,触发原始方法调用
Object result = mi.proceed();
return result;
} finally {
// 2. 无论是否异常,执行后置通知(@After)
invokeAdviceMethod(...);
}
}
- 调用
mi.proceed()
时,currentInterceptorIndex
已达到链的末尾(1 == 1
),因此执行原始方法invokeJoinpoint()
→ 打印 "执行业务逻辑"。 -
最后,在
finally
块中打印 "AOP 后置通知"。
3. 执行顺序总结
虽然拦截器链的顺序是 @Before
→ @After
,但实际执行顺序是:
@Before → 原始方法 → @After
这是因为 @After
对应的拦截器(AspectJAfterAdvice
)在它的 invoke()
方法中,先调用 mi.proceed()
触发后续逻辑(包括原始方法),然后在 finally
块中执行后置通知。
关键设计思想
-
递归式链式调用:每个拦截器在完成自身逻辑后,必须显式调用
mi.proceed()
才能推进链的执行。 -
后置通知的 finally 保证:
@After
的逻辑包裹在finally
块中,确保无论方法是否抛出异常都会执行。 - 拦截器顺序 ≠ 执行顺序:拦截器的排列顺序决定了它们拦截的优先级,但具体执行顺序由每个拦截器的内部逻辑决定。
验证方法
-
调试
ReflectiveMethodInvocation
:- 在
proceed()
方法中观察currentInterceptorIndex
的变化。 - 在
MethodBeforeAdviceInterceptor.invoke()
和AspectJAfterAdvice.invoke()
中设置断点,观察调用顺序。
- 在
-
查看拦截器链内容:
- 在
CglibAopProxy.DynamicAdvisedInterceptor.intercept()
方法中,检查拦截器链的组成:
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
- 在
-
观察
AspectJAfterAdvice
的invoke()
方法:- 注意
mi.proceed()
的调用触发原始方法,而@After
逻辑在finally
块中执行。
- 注意
总结流程图
1. 代理方法调用
│
└─ ReflectiveMethodInvocation.proceed()
│
├─ 执行 MethodBeforeAdviceInterceptor(@Before)
│ │
│ └─ 调用 proceed() → 推进到下一个拦截器
│
├─ 执行 AspectJAfterAdvice(@After)
│ │
│ ├─ 调用 proceed() → 触发原始方法
│ │ │
│ │ └─ 执行原始方法(TargetService.doSomething())
│ │
│ └─ finally 块执行 @After 逻辑
│
└─ 返回结果
通过这种设计,Spring AOP 实现了 @Before
→ 原始方法 → @After
的执行顺序,而拦截器链的物理顺序只是实现这一逻辑的手段。
Top comments (0)