Spring AOP 源码深度剖析——从代理创建到拦截链的执行过程

📅 2026/7/11 21:07:43
Spring AOP 源码深度剖析——从代理创建到拦截链的执行过程
Spring AOP 源码深度剖析——从代理创建到拦截链的执行过程一、AOP 的本质代理模式与横切关注点面向切面编程Aspect-Oriented Programming是 Spring 框架的核心能力之一它通过动态代理技术在方法调用前后织入横切逻辑如日志记录、事务管理、权限校验等。理解 AOP 的底层原理需要从两个层面入手代理对象的创建机制和拦截链的调用过程。Spring AOP 的代理创建有一个基本原则如果目标类实现了接口默认使用 JDK 动态代理如果目标类没有实现任何接口则使用 CGLIB 动态代理。在 Spring Boot 2.0 之后官方将默认策略改为始终使用 CGLIB 代理因为 CGLIB 在大多数场景下性能更为稳定且不受接口限制。二、代理创建的完整链路Spring 容器的 Bean 后处理器BeanPostProcessor是 AOP 代理创建的关键入口。当容器完成 Bean 的属性填充后会遍历所有已注册的后处理器。AbstractAutoProxyCreator是核心类它实现了SmartInstantiationAwareBeanPostProcessor接口在postProcessAfterInitialization方法中完成代理的创建。代理创建的决策流程如下graph TD A[Bean 实例化与属性填充] -- B[AbstractAutoProxyCreator.postProcessAfterInitialization] B -- C{wrapIfNecessary} C -- D[获取匹配的 Advisor 列表] D -- E{Advisor 列表是否为空?} E --|是| F[返回原始 Bean] E --|否| G[createProxy] G -- H[ProxyFactory.getProxy] H -- I{目标类是否实现了接口?} I --|是| J[JdkDynamicAopProxy] I --|否| K[ObjenesisCglibAopProxy] J -- L[生成 JDK 代理对象] K -- M[生成 CGLIB 代理对象] L -- N[注册到容器] M -- N在createProxy方法中Spring 会创建一个ProxyFactory实例将匹配到的所有Advisor增强器添加到工厂中。Advisor包含两部分Pointcut切点决定哪些方法需要增强和Advice增强逻辑即具体要织入的代码。最终通过ProxyFactory.getProxy()返回代理对象。三、拦截链的执行机制当调用代理对象的方法时实际执行路径会经过一个责任链模式的拦截器链。以 JDK 动态代理为例JdkDynamicAopProxy实现了InvocationHandler接口其invoke方法是所有代理方法调用的总入口。invoke方法的核心逻辑是获取拦截器链。Spring 通过DefaultAdvisorChainFactory遍历所有配置的 Advisor使用 Pointcut 的matches方法判断当前方法是否需要被增强。匹配到的 Advisor 中的 Advice 会被适配为MethodInterceptor并加入拦截器链。拦截器链最终被封装为ReflectiveMethodInvocation对象通过递归调用proceed()方法实现链式执行sequenceDiagram participant Client as 调用方 participant Proxy as JdkDynamicAopProxy participant Chain as ReflectiveMethodInvocation participant Adv1 as 拦截器1(事务) participant Adv2 as 拦截器2(日志) participant Target as 目标方法 Client-Proxy: 调用方法 Proxy-Proxy: 获取拦截器链 Proxy-Chain: 创建 ReflectiveMethodInvocation Proxy-Chain: proceed() Chain-Chain: currentInterceptorIndex Chain-Adv1: invoke(this) Adv1-Chain: proceed()【事务开启】 Chain-Chain: currentInterceptorIndex Chain-Adv2: invoke(this) Adv2-Chain: proceed()【日志记录】 Chain-Chain: 索引越界执行目标方法 Chain-Target: invokeJoinpoint() Target--Chain: 返回结果 Chain--Adv2: 返回结果【日志完成】 Chain--Adv1: 返回结果【事务提交】 Chain--Proxy: 返回最终结果 Proxy--Client: 返回代理结果拦截器链执行的关键在于currentInterceptorIndex。每次调用proceed()时索引自增获取下一个拦截器并执行其invoke方法。当索引等于拦截器总数时意味着所有前置逻辑已执行完毕此时调用invokeJoinpoint()执行真正的目标方法。目标方法返回后执行流沿调用栈逐层返回每个拦截器的后置逻辑依次执行。四、核心源码解读以下是简化后的拦截器链执行核心逻辑展示了 Spring AOP 中责任链模式的实现import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Method; import java.util.List; /** * AOP 拦截器链执行的核心实现——ReflectiveMethodInvocation 简化版 * 展示了 Spring AOP 如何通过递归调用实现责任链模式 */ public class ReflectiveMethodInvocation implements MethodInvocation { /** 拦截器链列表 */ private final ListMethodInterceptor interceptors; /** 目标对象 */ private final Object target; /** 目标方法 */ private final Method method; /** 方法参数 */ private final Object[] arguments; /** 当前拦截器索引从 -1 开始 */ private int currentInterceptorIndex -1; public ReflectiveMethodInvocation( ListMethodInterceptor interceptors, Object target, Method method, Object[] arguments) { this.interceptors interceptors; this.target target; this.method method; this.arguments arguments; } /** * 核心方法责任链的递归递进 * 每次调用将索引 1获取下一个拦截器执行 * 当所有拦截器执行完毕后调用目标方法 */ Override public Object proceed() throws Throwable { // 索引递进获取下一个拦截器 this.currentInterceptorIndex; // 判断是否已经执行完所有拦截器 if (this.currentInterceptorIndex this.interceptors.size()) { // 所有前置通知已执行完毕执行目标方法 return invokeJoinpoint(); } // 获取当前拦截器 MethodInterceptor interceptor this.interceptors.get(this.currentInterceptorIndex); // 将当前对象(this)传递给拦截器形成递归调用链 // 拦截器在完成前置逻辑后必须回调 this.proceed() 才能继续执行后续拦截器 try { return interceptor.invoke(this); } catch (Exception e) { // 异常处理记录异常信息并重新抛出 System.err.println(拦截器 [ interceptor.getClass().getSimpleName() ] 执行异常: e.getMessage()); throw e; } } /** * 执行真正的目标方法 */ protected Object invokeJoinpoint() throws Throwable { try { // 设置方法为可访问处理私有方法场景 if (!method.isAccessible()) { method.setAccessible(true); } return method.invoke(this.target, this.arguments); } catch (Exception e) { // 目标方法执行异常包装为 InvocationTargetException System.err.println(目标方法 [ method.getName() ] 执行失败: e.getMessage()); throw e; } } Override public Object getThis() { return this.target; } Override public AccessibleObject getStaticPart() { return this.method; } Override public Method getMethod() { return this.method; } Override public Object[] getArguments() { return this.arguments; } }在 Spring 的实际实现中ReflectiveMethodInvocation还包含更多细节如ExposeInvocationInterceptor用于将当前调用暴露给 ThreadLocal、AspectJAfterThrowingAdvice处理异常通知、AfterReturningAdviceInterceptor处理后置返回通知等。从简化版代码可以看出整个链条的精髓在于currentInterceptorIndex的自增和递归回调——每个拦截器必须主动调用proceed()才能推动链条前进这种设计保证了拦截器的执行顺序严格可控。五、实战经验总结在实际项目中使用 Spring AOP 时有几点经验值得关注代理失效场景。同一个类内部的方法调用不会经过代理对象因此 AOP 不会生效。这是因为调用this.method()时直接引用了原始对象而非代理对象。解决方案包括通过AopContext.currentProxy()获取代理对象进行调用或将需要增强的方法拆分到不同的 Bean 中。性能考量。CGLIB 代理在创建阶段开销较大因为需要生成字节码子类。如果应用中存在大量需要 AOP 的 Bean 且启动时间敏感可以考虑对核心链路使用编译期织入AspectJ 的 compile-time weaving来替代运行时代理。拦截器顺序控制。多个切面的执行顺序由Order注解控制数值越小优先级越高越先执行前置逻辑、越后执行后置逻辑。这一点在事务和自定义切面共存时尤为重要——事务切面通常应处于最外层确保自定义切面的执行被事务包裹。深入理解 AOP 的源码原理有助于在实际开发中准确判断代理行为、排查代理失效问题以及在性能优化时做出正确的技术决策。