当前位置: 首页 > news >正文

Spring AOP 设计解密:代理对象生成、拦截器链调度与注解适配全流程源码解析

文章目录

    • 主要基础接口
      • 1. Advice 通知接口:增强逻辑的载体
      • 2. Pointcut 切点接口:精准定位需要增强的方法
      • 3. Advisor 通知器接口:组合 Pointcut 和 Advice
    • 创建代理对象的触发入口
      • ProxyFactoryBean
        • 1. 生成代理对象的源码入口
        • 2. 初始化 Advisor 链
        • 3. 生成单例代理对象
    • 动态代理选择机制
    • 代理对象创建过程
      • 1. JDK动态代理实现(JdkDynamicAopProxy)
      • 2. CGLIB代理实现(ObjenesisCglibAopProxy)
    • Spring AOP 拦截器调用的实现
      • 1. JdkDynamicAopProxy 的 invoke() 拦截
      • 2. CglibAopProxy 的 intercept() 拦截
      • 3. 目标对象中目标方法的调用
      • 4. AOP 拦截器链的调用
      • 5. 配置通知器
      • 6. Advice 通知的实现
    • 代理执行流程(核心拦截器链机制)
      • 执行链构建流程(以JDK代理实现为例的图示)
    • 源码分析实践建议

深入Spring AOP源码, 在Spring AOP的设计实现中主要使用了 JDK 动态代理,在特定场景下(被代理对象没有实现的接口)也用到了 CGLIB 生成代理。通过源码设计可以看到,首先是为目标对象建立了代理对象(是 JDK 动态代理CGLIB 实现)。然后启动为代理对象配置的拦截器对横切面(目标方法集合)进行相应的增强,将 AOP 的横切面设计Proxy 模式有效地结合起来,实现了在 AOP 中定义好的各种织入方式。

主要基础接口

在Spring AOP框架中,AdvicePointcutAdvisor是三个核心接口,共同定义了切面的行为。

1. Advice 通知接口:增强逻辑的载体

本接口定义了切面的增强方式,封装在连接点执行的横切逻辑;如:前置增强 BeforeAdvice,后置增强 AfterAdvice,异常增强 ThrowsAdvice,环绕增强MethodInterceptor(AOP Alliance 标准) 等。看两个主要的子接口的源码:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2. Pointcut 切点接口:精准定位需要增强的方法

本接口用来定义需要增强的目标方法的集合,一般使用正则表达式去匹配筛选指定范围内的所有满足条件的目标方法。作用是确定在哪些连接点(Joinpoint)(如方法执行)应用增强逻辑。Pointcut 接口有很多实现,我们主要看一下 JdkRegexpMethodPointcutNameMatchMethodPointcut 的实现原理:

在这里插入图片描述
JdkRegexpMethodPointcut 的实现源码

在这里插入图片描述

NameMatchMethodPointcut 的实现源码

在这里插入图片描述

3. Advisor 通知器接口:组合 Pointcut 和 Advice

PointcutAdvice 有效地结合在一起组合成一个完整的切面定义。它定义了在哪些方法(Pointcut)上执行哪些动作(Advice)。下面看一下 DefaultPointcutAdvisor 的源码实现,它通过持有 PointcutAdvice 属性来将两者有效地结合在一起。

在这里插入图片描述

DefaultPointcutAdvisor 实现源码
在这里插入图片描述
在这里插入图片描述

创建代理对象的触发入口

创建代理的触发点在 Spring AOP 中确实是多地方, Spring AOP 的代理创建机制被设计得相当灵活,可以通过不同层次和方式的 API 或配置来触发。

  • 编程式创建 - 最底层/最灵活 (ProxyFactory):开发者直接实例化 ProxyFactory
  • 声明式创建 - IoC 容器集成 (ProxyFactoryBean ):当 Spring 容器实例化并配置定义在 XML 或 Java Config 中的 ProxyFactoryBean Bean 时。是早期 Spring AOP 配置的主要方式之一。
  • 自动代理创建器 (AbstractAutoProxyCreator 及其子类 - 容器级自动化):Spring 容器在 Bean 初始化之后(postProcessAfterInitialization 方法) 调用这些自动代理创建器。创建器检查当前 Bean 是否匹配配置的 Pointcut(即是否需要被代理)。

这里主要以 ProxyFactoryBean 的实现为例,对 AOP 的实现原理进行分析。

ProxyFactoryBean

1. 生成代理对象的源码入口

ProxyFactoryBeangetObject() 方法先对通知器链进行了初始化,然后根据被代理对象类型的不同,生成代理对象。

在这里插入图片描述

2. 初始化 Advisor 链

在这里插入图片描述
生成单例(singleton)的代理对象在 getSingletonInstance() 方法中完成,这是 ProxyFactoryBean 生成 AopProxy 代理对象的调用入口。代理对象会封装对 target 对象的调用,针对 target 对象的方法调用会被这里生成的代理对象所拦截。

3. 生成单例代理对象

在这里插入图片描述

上面的 createAopProxy() 方法,调用了 ProxyFactoryBean 的父类 ProxyCreatorSupport 中的实现。

在这里插入图片描述
接着就进入并比较重要的核心源码类DefaultAopProxyFactory,它是AopProxyFactory 接口的实现类;主要看createAopProxy(AdvisedSupport config)方法。

动态代理选择机制

Spring AOP的核心代理选择逻辑由DefaultAopProxyFactory实现,其决策流程如下:

在这里插入图片描述
代理选择策略:

  1. 强制CGLIB场景:
    • 显式设置proxyTargetClass=true
    • 目标类未实现任何接口(除SpringProxy外)
    • 历史遗留的optimize=true(Spring 5+已废弃)
  2. 强制JDK代理场景:
    • 目标对象是接口类型
    • 目标对象已是JDK代理类
  3. 默认策略:目标类实现接口时使用JDK代理

设计启示:该策略模式实现使Spring能灵活应对不同代理需求,同时屏蔽底层技术差异。

代理对象创建过程

1. JDK动态代理实现(JdkDynamicAopProxy)

JDK 动态代理 生成 AopProxy 代理对象

在这里插入图片描述
通过 JdkDynamicAopProxy 的源码可以非常清楚地看到,其使用了 JDK 动态代理 的方式生成了 代理对象。JdkDynamicAopProxy 实现了 InvocationHandler 接口,并通过 java.lang.reflect.ProxynewProxyInstance()静态方法 生成代理对象并返回。

2. CGLIB代理实现(ObjenesisCglibAopProxy)

CGLIB 生成 AopProxy 代理对象

在这里插入图片描述
在为目标对象生成代理对象之后,在调用 代理对象 的目标方法时,目标方法会进行 invoke()回调(JDK 动态代理) 或 callbacks()回调(CGLIB),然后就可以在回调方法中对目标对象的目标方法进行拦截和增强处理了。

Spring AOP 拦截器调用的实现

代理执行流程(核心拦截器链机制)

在通过 JDK 的 Proxy 类生成代理对象时,相关的拦截器已经配置到了代理对象内部持有的 InvocationHandler 实例 (对于 JDK 代理是 JdkDynamicAopProxy) 所引用的 AdvisedSupport 配置对象中。拦截器最后起作用,是通过调用代理对象的目标方法时,代理机制会触发其关联的处理器 (InvocationHandler.invoke()),这些处理器回调方法会从 AdvisedSupport 中获取拦截器链并执行。

在通过 CGLIB 生成代理对象时,相关的拦截器已经配置到了代理对象内部持有的 CGLIB Callback 实例 (核心是 DynamicAdvisedInterceptor) 所引用的 AdvisedSupport 配置对象中。当调用代理对象的目标方法时,代理机制会触发其关联的处理器 (MethodInterceptor.intercept()),这些处理器回调方法会从 AdvisedSupport 中获取拦截器链并执行。

图解关系

+---------------------+       (配置阶段)
|   ProxyFactoryBean   | -------------------+
| (or ProxyFactory)    |                    |
+----------+----------+                     || Configures                     | Holdsv                                v
+---------------------+       +--------------------------+
|     AdvisedSupport   | <---- | JdkDynamicAopProxy       | (JDK Handler)
| - TargetSource       |       | - advised: AdvisedSupport |------------------+
| - List<Advice>       |       +--------------------------+                  |
| - List<Advisor>      |                                                    |
| - ...                |       +--------------------------+                  |
+---------------------+       | DynamicAdvisedInterceptor | (CGLIB Callback) || - advised: AdvisedSupport |------------------++--------------------------+^                           ^| Associated with            | Associated with|                           |
+---------------------+       +----+--------+             +-----+--------+
|   Proxy Object      |       | JDK Proxy   |             | CGLIB Proxy  |
| (Implements         |       | Object      |             | (Subclass)   |
|  interface(s))      |       +-------------+             +--------------+
| OR                  |           |                             |
| (Subclass)          |           | Holds                       | Holds
+---------------------+           v                             v+------------------+           +-------------------+| InvocationHandler|           | Callback (e.g.    || (JdkDynamicAopProxy)|           | DynamicAdvised..) |+------------------+           +-------------------+|                             || (invoke called)             | (intercept called)v                             v[Gets interceptor chain from AdvisedSupport][Creates MethodInvocation][Runs interceptor chain -> calls target method]

前面已经通过两种不同的方式生成了 AopProxy 代理对象,下面我们先看一下 JdkDynamicAopProxy 中的 invoke()回调方法 中对拦截器调用的实现。

1. JdkDynamicAopProxy 的 invoke() 拦截

在这里插入图片描述

2. CglibAopProxy 的 intercept() 拦截

CglibAopProxyintercept() 回调方法实现和 JdkDynamicAopProxyinvoke() 非常相似,只是在 CglibAopProxy 中构造 CglibMethodInvocation 对象来完成拦截器链的调用,而在 JdkDynamicAopProxy 中则是通过构造 ReflectiveMethodInvocation 对象来完成的。
在这里插入图片描述

3. 目标对象中目标方法的调用

对目标对象中目标方法的调用,JdkDynamicAopProxy是在 AopUtils 工具类中利用反射机制完成的,具体代码如下。
在这里插入图片描述
对目标对象中目标方法的调用,CglibAopProxy是直接通过调用 MethodProxyinvoke()MethodProxyinvoke 方法用于在相同类型的另一个对象上调用原始方法(非拦截方法)。它允许直接调用被代理的方法,绕过 CGLIB 应用的任何拦截器或增强。具体代码如下。
在这里插入图片描述

4. AOP 拦截器链的调用

JdkDynamicAopProxyCglibAopProxy 虽然使用了不同的代理对象,但对 AOP 拦截的处理却是相同的,都是通过 ReflectiveMethodInvocationproceed() 方法实现的。

在这里插入图片描述

责任链模式:通过递归调用实现拦截器链的顺序执行,每个拦截器控制是否向下传递

思考点:为什么拦截器链为空时,JDK 代理:直接通过 AopUtils.invokeJoinpointUsingReflection(target, method, args) 调用;而CGLIB 代理:直接通过 methodProxy.invoke(target, args) 调用;拦截器链不为空时,两种代理统一使用 AopUtils.invokeJoinpointUsingReflection(target, method, args) 调用原始方法?

解答: 这种设计是 Spring 在架构一致性、维护成本和性能优化之间做出的合理权衡。虽然理论上 CGLIB 在拦截链场景也能用 methodProxy.invoke(),但实际收益微乎其微,不值得为此破坏架构的纯净性。

到此, Spring AOP的过程就结束了, 下面在看下拦截器链(配置的通知器)的获取源码细节。

5. 配置通知器

由源码可知配置的通知器是在AdvisedSupport 类中获取的;AdvisedSupport 中实现了获取拦截器链的方法,并使用了缓存
在这里插入图片描述

在这里插入图片描述

获取拦截器链的工作是由 AdvisorChainFactory 完成的,他是一个拦截器链的生成工厂。由于 AdvisorChainFactory 接口只有一个默认实现类 DefaultAdvisorChainFactory,所以我们直接看这个类中的实现。

在这里插入图片描述
由上面源码可看出 advisor 通知器(拦截器链)是从 AdvisedSupport 中获取的,而 advisor 的初始化则是在 ProxyFactoryBeangetObject() 方法中完成的,在前面我们已经看过源码了。

注意,Advisor 本身就被配置为 bean,所以它的获取也是通过 IoC 容器 获得的。

6. Advice 通知的实现

DefaultAdvisorChainFactory 类中的 getInterceptorsAndDynamicInterceptionAdvice() 方法我们可以看到,其通过 AdvisorAdapterRegistry 实例对象的 getInterceptors() 方法,利用配置的 advisor 完成了对拦截器的适配和注册
DefaultAdvisorAdapterRegistrygetInterceptors()方法 封装了 advice 织入实现的入口。

在这里插入图片描述

DefaultAdvisorAdapterRegistry 的实现中可以看到,其使用了MethodBeforeAdviceAdapterAfterReturningAdviceAdapterThrowsAdviceAdapter 等一系列的 AdviceAdapter 适配器;它们完全和 Advice 的类型一一对应,它们都是实现了 AdviceAdapter 接口的同一层次类,各自承担着不同的适配任务,一对一地服务于不同的 Advice 实现。
下面我们主要看下 MethodBeforeAdviceAdapter 的源码实现。

在这里插入图片描述

可以看到,其中的 getInterceptor()方法 把 AdviceAdvisor 中取出来,然后创建了一个 MethodBeforeAdviceInterceptor 对象,并返回,这个对象中持有对 Advice 的引用。下面我们看一下 MethodBeforeAdviceInterceptor 拦截器的源码实现。

在这里插入图片描述
可以看到,MethodBeforeAdviceInterceptorinvoke()方法 先是触发了 advice 的 before()方法,然后才是 MethodInvocation 的 proceed()方法调用。

简单回顾一下之前的代码,在 AopProxy 代理对象 触发的 ReflectiveMethodInvocationproceed() 中,在取得 拦截器 interceptor 后调用了其 invoke()方法。按照 AOP 的配置规则,ReflectiveMethodInvocation 触发的拦截器 invoke()回调,最终会根据 Advice 类型的不同,触发 Spring 对不同的 Advice 的拦截器封装,比如 MethodBeforeAdvice 最终会触发 MethodBeforeAdviceInterceptorinvoke()回调,其它两个拦截器与此类似。

代理执行流程(核心拦截器链机制)

执行链构建流程(以JDK代理实现为例的图示)

在这里插入图片描述

源码分析实践建议

  1. 调试技巧
# 启用代理类保存
System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");# 开启AOP调试日志
logging.level.org.springframework.aop=DEBUG
  1. 性能优化点
    • 避免宽泛切点表达式(如execution(* *.*(..))
    • 优先使用@annotation精确匹配注解方法
    • 自调用问题通过AopContext.currentProxy()解决
  2. 核心源码路径:
    • 代理创建:org.springframework.aop.framework.DefaultAopProxyFactory
    • 执行链:org.springframework.aop.framework.ReflectiveMethodInvocation
    • 注解解析:org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator

最佳实践:结合@EnableAspectJAutoProxy(exposeProxy=true)解决内部调用代理失效问题,深度理解Spring AOP需把握代理创建时机执行链机制注解适配原理三大核心环节。

通过源码分析可见,Spring AOP通过精妙的责任链模式动态代理技术的结合,实现了声明式切面编程能力,其设计充分体现了开闭原则单一职责原则,是框架设计中模式应用的典范。很值得我们学习借鉴,与诸君共勉吧!


End!

http://www.dtcms.com/a/269158.html

相关文章:

  • 學習網頁製作
  • 应用俄文OCR技术,为跨语言交流与数字化管理提供更强大的支持
  • 【前端UI】【ShadCN UI】一个干净、语义化、可拓展、完全可控的“代码级组件模板库”
  • 选择排序算法详解(含Python实现)
  • python中MongoDB操作实践:查询文档、批量插入文档、更新文档、删除文档
  • 指尖上的魔法:优雅高效的Linux命令手册
  • GitHub 趋势日报 (2025年07月06日)
  • PyTorch 详细安装教程及核心API使用指南
  • Chatbox➕知识库➕Mcp = 机器学习私人语音助手
  • 分层Agent
  • turborepo 如何解决git管理包过大的问题
  • 二、Docker安装部署教程
  • 20250707-4-Kubernetes 集群部署、配置和验证-kubeconfig_笔记
  • 人工智能赋能极端气候事件管理:重构风险预警与应急响应体系
  • 汽车功能安全系统阶段开发【技术安全需求TSR】4
  • 多维度数据资产测绘技术在安全管控平台中的应用实践
  • RKAndroid11-系统设置新增开关选项
  • 1. http 有哪些版本,你是用的哪个版本,怎么查看
  • 构建分布式高防架构实现业务零中断
  • 2025最新如何解决VSCode远程连接开发机失败/解决方案大全
  • 提示工程(Prompt Engineering)研究进展
  • Spring Data JPA基本方法调用规律
  • web渗透之指纹识别1
  • Shader面试题100道之(1-20)
  • PX4无人机上的返航操作和参数解读
  • 华为OD机试 2025B卷 - 最长的指定瑕疵度的元音子串 (C++PythonJAVAJSC语言)
  • DCN2:大规模推荐系统中的碰撞权重与显式交叉层协同优化
  • C++ tcp客户端处理重连问题
  • 3S技术+ArcGIS/ENVI全流程实战:水文、气象、灾害、生态、环境及卫生等领域应用
  • 前端工程化速通——①ES6