本文将结合代码实现,深入剖析AOP(面向切面编程)调用链的核心原理。通过完整的示例代码和逐层解析,揭示递归调用与责任链模式如何协同构建方法调用栈的"洋葱模型"。
一、AOP调用链的核心设计
AOP调用链的核心是递归+责任链的协同机制:
- 责任链模式:每个拦截器作为处理节点,组成执行链
- 递归推进:通过状态索引控制链式调用顺序
- 洋葱模型:拦截器层层包裹目标方法,形成"前置→内层→后置"结构
关键数据结构 :
MyMethodInvocation
维护三个核心状态:
currentIndex
:当前执行的拦截器位置interceptorList
:有序的拦截器链target/method
:目标方法信息
二、核心组件解析
1. 目标方法(业务逻辑)
java
static class CallChainBeanA {
public void foo() {
log.info("[CallChainBeanA] 执行了foo()方法(实际业务逻辑)");
}
}
作为调用链的最内层,包含实际业务逻辑,无任何拦截逻辑。
2. 拦截器实现(环绕通知)
拦截器A(外层):
java
static class CallChainAdviceA implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
log.info("╭── [AdviceA] 前置执行 (堆栈深度: {})", Thread.currentThread().getStackTrace().length);
log.debug("│ [AdviceA] 开始构建调用栈帧");
// JVM在此处压入新的栈帧(invocation.proceed)
Object result = invocation.proceed(); // 关键调用点:推进调用链
log.debug("│ [AdviceA] 栈帧返回,恢复执行");
log.info("╰── [AdviceA] 后置执行 (结果: {})", result);
return result;
}
}
拦截器B(中层):
java
static class CallChainAdviceB implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
log.info("│ ╭── [AdviceB] 前置执行 (堆栈深度: {})", Thread.currentThread().getStackTrace().length);
log.debug("│ │ [AdviceB] 创建中间层栈帧");
// 继续推进调用链(可能指向下一个拦截器或目标方法)
Object result = invocation.proceed();
log.debug("│ │ [AdviceB] 中间层栈帧返回");
log.info("│ ╰── [AdviceB] 后置执行");
return result;
}
}
设计要点:
- 每个拦截器必须调用
proceed()
推进链- 前置/后置逻辑形成对称结构
- 日志缩进直观展示调用层级
三、递归引擎:MyMethodInvocation
核心方法proceed()
实现链式推进:
java
@Override
public Object proceed() throws Throwable {
log.debug("├─ 推进调用链 [位置: {}/{}]", currentIndex, interceptorList.size());
// 递归基:所有拦截器已执行完毕,执行目标方法
if (currentIndex >= interceptorList.size()) {
log.info("│ ╭── 执行目标方法 [调用栈深度: {}]", Thread.currentThread().getStackTrace().length);
log.debug("│ │ ▌ 反射调用: {}.{}()",
target.getClass().getSimpleName(), method.getName());
long startTime = System.nanoTime();
Object result = invokeTargetMethod(); // 实际的方法调用点
long duration = System.nanoTime() - startTime;
log.debug("│ │ ▌ 执行时间: {} ns", duration);
log.info("│ ╰── 目标方法完成 [结果: {}]", result);
return result;
}
// 获取当前拦截器
MethodInterceptor interceptor = interceptorList.get(currentIndex);
log.debug("│ ├─ 获取拦截器 [{}]: {}", currentIndex,
interceptor.getClass().getSimpleName());
// 状态推进:索引+1(准备进入下一层递归)
currentIndex++;
// 关键递归步骤:调用拦截器的invoke方法(将自身作为参数传入)
log.debug("│ │ ╭── 进入拦截器调用 [深度提升]");
Object result = interceptor.invoke(this);
log.debug("│ │ ╰── 拦截器返回 [恢复调用链状态]");
return result;
}
递归过程示例:
返回结果 返回结果 返回结果 返回结果 proceed index=2 执行目标方法
四、调用链执行全流程分析
1. 初始化阶段
java
// 创建目标对象
CallChainBeanA beanA = new CallChainBeanA();
// 构建拦截器链(执行顺序:A→B)
List<MethodInterceptor> interceptors = List.of(
new CallChainAdviceA(),
new CallChainAdviceB()
);
// 创建调用入口
MyMethodInvocation invocation = new MyMethodInvocation(
beanA, fooMethod, new Object[0], interceptors
);
2. 调用链执行日志分析
╭── [AdviceA] 前置执行 (堆栈深度: 4)
│ ╭── [AdviceB] 前置执行 (堆栈深度: 6)
│ ╭── 执行目标方法 [调用栈深度: 7]
│ │ [CallChainBeanA] 执行了foo()方法(实际业务逻辑)
│ ╰── 目标方法完成 [结果: null]
│ ╰── [AdviceB] 后置执行
╰── [AdviceA] 后置执行
栈帧变化示意图:
AdviceA 前置日志 AdviceB 前置日志 目标方法 后置日志 后置日志
五、关键技术原理
-
双栈协同机制
- JVM方法栈:维护原生方法调用关系
- 调用链栈:通过
currentIndex
记录自定义状态
java// 在拦截器中获取实际栈深度 Thread.currentThread().getStackTrace().length
-
递归的终止条件
javaif (currentIndex >= interceptorList.size()) { // 递归基:执行目标方法 return method.invoke(target, args); }
-
异常处理机制
javaprivate Object invokeTargetMethod() throws Throwable { try { return method.invoke(target, args); } catch (InvocationTargetException e) { throw e.getTargetException(); // 解包原始异常 } catch (Exception e) { throw new RuntimeException("调用目标方法失败", e); } }
六、设计模式应用
-
责任链模式
- 拦截器实现统一接口
MethodInterceptor
- 链式传递执行权
- 拦截器实现统一接口
-
递归模式
- 状态控制:
currentIndex
- 递归步骤:
interceptor.invoke(this)
- 终止条件:执行目标方法
- 状态控制:
-
代理模式
- 所有方法调用通过
MethodInvocation
对象转发 - 拦截器透明增强目标方法
- 所有方法调用通过
结语
通过本文实现的调用链案例,我们揭示了AOP的核心工作原理:
- 洋葱模型:拦截器按顺序层层包裹目标方法
- 递归驱动:通过索引状态控制链式调用
- 双栈协同:JVM栈帧与自定义状态协同工作
这种设计在Spring AOP、Dubbo过滤器链等框架中广泛应用,其原理对于编写高性能拦截器和排查调用链问题至关重要。
完整代码
java
package com.dwl.call_chain;
import jakarta.annotation.Nonnull;
import lombok.Data;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
/**
* @ClassName CallChainCase
* @Description AOP调用链实现原理的深入演示,展示拦截器链的执行机制
* @Version 1.0.0
* @Date 2025
* @Author By Dwl
* <p>
* 核心原理:递归+责任链模式实现的方法调用栈
* 设计要点:
* 1. "洋葱模型"结构:每个拦截器包裹下一个拦截器或目标方法
* 2. 递归推进机制:通过索引计数器控制执行流程
* 3. 方法调用栈:JVM调用栈+自定义调用链状态的协同工作
*/
@Slf4j
public class CallChainCase {
/**
* 目标Bean类,包含需要被拦截的业务方法
* 设计说明:模拟实际的业务对象,无拦截器相关逻辑
*/
static class CallChainBeanA {
public void foo() {
log.info("[CallChainBeanA] 执行了foo()方法(实际业务逻辑)");
}
}
/**
* 拦截器A实现(环绕通知)
* 执行逻辑:
* 1. 前置增强
* 2. 调用proceed()推进调用链
* 3. 后置增强
* <p>
* 方法栈深度原理:
* ┌───────────────────┐
* │ CallChainAdviceA │<─── 最外层栈帧(最先入栈)
* ├───────────────────┤
* │ CallChainAdviceB │
* ├───────────────────┤
* │ 目标方法foo() │
* └───────────────────┘
*/
static class CallChainAdviceA implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
log.info("╭── [AdviceA] 前置执行 (堆栈深度: {})", Thread.currentThread().getStackTrace().length);
log.debug("│ [AdviceA] 开始构建调用栈帧");
// JVM在此处压入新的栈帧(invocation.proceed)
Object result = invocation.proceed(); // 关键调用点:推进调用链
log.debug("│ [AdviceA] 栈帧返回,恢复执行");
log.info("╰── [AdviceA] 后置执行 (结果: {})", result);
return result;
}
}
/**
* 拦截器B实现(环绕通知)
* 执行顺序说明:
* 1. 当AdviceA调用proceed()时进入此处
* 2. AdviceB是中间层拦截器
*/
static class CallChainAdviceB implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
log.info("│ ╭── [AdviceB] 前置执行 (堆栈深度: {})", Thread.currentThread().getStackTrace().length);
log.debug("│ │ [AdviceB] 创建中间层栈帧");
// 继续推进调用链(可能指向下一个拦截器或目标方法)
Object result = invocation.proceed();
log.debug("│ │ [AdviceB] 中间层栈帧返回");
log.info("│ ╰── [AdviceB] 后置执行");
return result;
}
}
/**
* 自定义方法调用实现(核心引擎)
* 功能:管理拦截器链的执行顺序和状态
* <p>
* 设计原理:
* 1. 状态跟踪:currentIndex记录当前执行位置
* 2. 递归终止条件:当所有拦截器执行完毕后调用目标方法
* 3. 链式推进:递归调用interceptor.invoke(this)
* <p>
* 工作流程伪代码:
* procedure proceed():
* if 所有拦截器已执行:
* 执行目标方法 // 递归基
* else:
* 获取当前拦截器
* 索引位置+1
* 执行拦截器.invoke(this) // 递归步骤
*/
@Data
static class MyMethodInvocation implements MethodInvocation {
private Object target; // 目标对象实例
private Method method; // 目标方法对象
private Object[] args; // 方法参数
private List<MethodInterceptor> interceptorList; // 拦截器链
private int currentIndex = 0; // 当前执行位置(核心状态跟踪器)
public MyMethodInvocation(Object target, Method method, Object[] args,
List<MethodInterceptor> interceptorList) {
this.target = target;
this.method = method;
this.args = args;
this.interceptorList = interceptorList;
log.debug("▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄");
log.debug("▌ 创建调用链对象 [方法: {}]", method.getName());
log.debug("▌ 目标对象: {}", target.getClass().getSimpleName());
log.debug("▌ 拦截器数量: {}", interceptorList.size());
log.debug("▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀");
}
@Override
@NonNull
public Method getMethod() {
return this.method;
}
@Override
@Nonnull
public Object[] getArguments() {
return args;
}
/**
* 核心方法:推进调用链执行
* 递归流程详解:
* 1. 当currentIndex = N (拦截器数量)时达到递归基
* 2. 每次proceed()调用会使currentIndex+1
* 3. 递归深度 = 拦截器数量 + 1 (目标方法)
* <p>
* 递归调用栈图示:
* ┌─────────────────┐
* │ proceed() │ currentIndex=0 → AdviceA
* ├─────────────────┤
* │ proceed() │ currentIndex=1 → AdviceB
* ├─────────────────┤
* │ proceed() │ currentIndex=2 → 目标方法
* └─────────────────┘
*/
@Override
public Object proceed() throws Throwable {
log.debug("├─ 推进调用链 [位置: {}/{}]", currentIndex, interceptorList.size());
// 递归基:所有拦截器已执行完毕,执行目标方法
if (currentIndex >= interceptorList.size()) {
log.info("│ ╭── 执行目标方法 [调用栈深度: {}]", Thread.currentThread().getStackTrace().length);
log.debug("│ │ ▌ 反射调用: {}.{}()",
target.getClass().getSimpleName(), method.getName());
long startTime = System.nanoTime();
Object result = invokeTargetMethod(); // 实际的方法调用点
long duration = System.nanoTime() - startTime;
log.debug("│ │ ▌ 执行时间: {} ns", duration);
log.info("│ ╰── 目标方法完成 [结果: {}]", result);
return result;
}
// 获取当前拦截器
MethodInterceptor interceptor = interceptorList.get(currentIndex);
log.debug("│ ├─ 获取拦截器 [{}]: {}", currentIndex,
interceptor.getClass().getSimpleName());
// 状态推进:索引+1(准备进入下一层递归)
currentIndex++;
// 关键递归步骤:调用拦截器的invoke方法(将自身作为参数传入)
log.debug("│ │ ╭── 进入拦截器调用 [深度提升]");
Object result = interceptor.invoke(this);
log.debug("│ │ ╰── 拦截器返回 [恢复调用链状态]");
return result;
}
/**
* 执行目标方法(安全处理)
* 设计要点:单独封装反射调用,处理异常情况
*/
private Object invokeTargetMethod() throws Throwable {
try {
return method.invoke(target, args);
} catch (InvocationTargetException e) {
throw e.getTargetException(); // 解包原始异常
} catch (Exception e) {
throw new RuntimeException("调用目标方法失败", e);
}
}
@Override
public Object getThis() {
return target;
}
@Override
@Nonnull
public AccessibleObject getStaticPart() {
return method;
}
}
public static void main(String[] args) throws Throwable {
log.info("\n\n============== 调用链执行流程演示 ==============");
log.info(" (递归+责任链模式实现)\n");
// 创建目标对象实例
CallChainBeanA beanA = new CallChainBeanA();
log.debug("▶ 实例化目标对象: {}", beanA.getClass().getSimpleName());
// 创建拦截器链(执行顺序:A → B → 目标方法)
List<MethodInterceptor> interceptors = List.of(
new CallChainAdviceA(),
new CallChainAdviceB()
);
log.debug("▶ 创建拦截器链: [AdviceA, AdviceB]");
// 获取目标方法对象(反射)
Method fooMethod = beanA.getClass().getMethod("foo");
log.debug("▶ 获取目标方法: {}", fooMethod);
// 创建调用链入口
log.info("\n[主程序] 创建方法调用入口点");
MyMethodInvocation invocation = new MyMethodInvocation(
beanA, fooMethod, new Object[0], interceptors
);
log.info("\n[主程序] 开始执行调用链(初始proceed调用)");
invocation.proceed();
log.info("\n[主程序] 调用链执行完成");
log.info("\n============== 执行流程结束 ==============");
}
}