Spring AOP的实现原理 ?

article/2025/9/18 10:15:45

Spring AOP的实现原理 ? - 知乎

AOP的实现,最关键的有两步:

  • 得到代理对象
  • 利用递归责任链执行前后置通知及目标方法

IOC容器初始化时,对于涉及AOP操作的目标类,其实Spring返回的是代理对象,而不是目标类的实例。至于Spring是如何创建AOP代理对象的,这里不做讨论,我们只讨论得到代理对象后的链式调用流程。

代理对象proxy其实包含了很多东西,比如:

  • 目标对象
  • 增强器
  • ...

之前我曾经写过一篇动态代理相关的回答:Java 动态代理作用是什么?

大概就是讲了以下两点:

  • 代理对象最终都会间接调用目标对象的同名方法,比如proxy.add() --> target.add()
  • 但代理对象允许在调用add()前后添加一些增强代码,作为功能扩展

即,调用代理对象的方法最终都会“转嫁”成调用目标方法,但是在调用前后会执行一些其他操作,我称这些其他操作为“增强代码”,本质上就是上面提到的增强器。

代理对象方法 = 拦截器链 + 目标对象方法

比如,JDK动态代理中,我们可以在invoke()方法中得到target并调用target.add(),并在前后加增强代码

AOP返回的代理对象也不例外。

现在假设代理对象proxy调用了某个方法,而这个方法会触发CglibAopProxy.intercept()。先不要理会为啥会触发这个方法,反正人家就是这样设定的。我们来看看intercept()方法:

intercept():

  • 没有拦截器链
    • 直接执行目标方法
  • 有拦截器链
    • 传入拦截器链和目标对象,最终new CglibMethodInvocation(...).proceed()

我们主要考虑有拦截器链的情况。

intercept()说穿了,就干了两件事:

  • 收集拦截器,做成链
  • 把拦截器链和目标对象等传入,执行new CglibMethodInvocation(...).proceed()
new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();

这里new了一个CglibMethodInvocation对象,你就把它理解成一个大杂烩,反正AOP功能需要的材料都在这里了,包括目标对象、拦截器链啥的。

我们来看看它的proceed()方法干了啥:

简化后的示意图:

也就是说,只要拦截器链没执行完,就不会执行目标方法。即:

  • 先执行全部的拦截器
  • 最后执行目标方法

我知道你看到这里,会有什么疑问:

既然拦截器都在目标方法前执行,怎么会出现AOP这种汉堡包式的“包夹”调用顺序?

before...
target.add()
afterReturning... ...

别急,接下来就是见证奇迹的时刻,我们看看拦截器的invoke()干了啥。

刚才说过了,拦截器是对增强器的包装。我们增强方法有哪些来着?Before/AfterReturning...等等,所以拦截器肯定也有对应的Before/AfterReturning...

我们先看Before拦截器:

我们发现:

  • 先调用了this.advice.before()。即,反射执行@Before方法。
  • 再调用了mi.proceed()。这个mi,就是我上一个截图传入的this,也就是CglibMethodInvocation对象。

再看After拦截器:

  • 先调用mi.proceed()
  • 后反射调用@After方法

先别管具体上下文环境以及方法含义,我就问你,单纯看语句调用顺序,Before拦截器和After拦截器有何不同?

答案是:

Before拦截器是先反射调用@Before,再调用 mi.proceed()。
而After拦截器是先调用mi.proceed(),再反射调用@AfterRetruning方法。

其实,只有Before是特殊的,其他拦截器都是先调用proceed(),再反射调用通知方法。

为什么Before拦截器是异类?因为这么多拦截器中,只有Before的通知方法是在目标方法前。所以这个差异,肯定和AOP的汉堡包式的“包夹”调用顺序有莫大关系!Before拦截器这种与众不同的语句顺序,导致了它可以出现在目标对象前执行。

我去,有点晕...

其实这里开始,就进入递归了。递归有时是比较晕的。

为了帮大家理清调用顺序,我画了一张图。不过艺术家的画,有时比较难懂,所以我要先给大家解读一下我的作画风格。比如一个方法如果有两句:

我会画成下面这样:

左边的代表上面的(先执行),右边的代表下面的(后执行)。

好,了解我画图的风格后,上主菜。

AOP递归责任链:

跟着调用栈,可以看到顺序是before---target.add()---after...

流程解读:

  • proxy.add()触发CglibAopProxy.intercept()
  • intercept()
    • 获取所有的拦截器,排好序后做出拦截器链(顺序和AOP执行顺序相反,before反而放链的末尾!)
    • 传入拦截器链和目标对象,new CglibMethodInvocation()并调用proceed()
  • proceed()先执行全部拦截器,最后执行目标方法
  • 目标方法的return是整个递归责任链的精华所在,就像一个弹簧,被压到最大限度,开始return了。所以,原路返回,执行每个拦截器invoke()方法中两个语句的下一句
  • 又由于Before拦截器是先反射执行通知方法后调用proceed(),而其他拦截器是先proceed()后反射,所以形成了“包夹”调用顺序

所以,虽然说拦截器全部执行完毕,才执行目标方法,但是拦截器的invoke()方法其实有两句语句,上一句只是递归调用下一个拦截器,只有等反射执行目标方法后,回来的路上才会真正执行通知方法!


http://chatgpt.dhexx.cn/article/tuWpcv1L.shtml

相关文章

AOP理解及底层原理

AOP 基础概念 一、概述 银行系统的简易取款流程如图: 将方框里的流程合为一个,另外系统还会有一个查询余额流程,如图: 这两个业务有一个共同的验证流程,如图: 为什么会有面向切面编程(AOP)&#xff…

Spring AOP原理分析一次看懂

什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构&…

AOP-底层原理

申明:学习笔记整理,内容非原创,仅供参考学习!视频详细地址如下: 尚硅谷Spring框架视频教程(spring5源码级讲解)_哔哩哔哩_bilibili 目录 一、AOP概念 二、AOP底层原理 三、JDK动态代理代码…

Spring AOP原理详解及实例

Spring AOP原理详解及实例 1.Spring AOP简介2.AOP与OOP对比3.AOP使用场景4.AOP相关概念5.AOP实例5.1 基于xml配置方式5.2 基于注解配置方式5.3 AspectJ切点函数 6.可能出现的问题及解决方法6.1 java.lang.IllegalArgumentException: error at :: 0 cant find referenced pointc…

JAVA AOP概念和实现原理 详解

// AOP 概念 1. 什么是AOP? // 面向切面(方面)编程 //利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率 // 不通过修改源代码方…

Spring IOC和AOP 原理彻底搞懂

本博中关于Spring的文章:Spring IOC和AOP原理,Spring事务原理探究,Spring配置文件属性详解,Spring中的代理模式 Spring提供了很多轻量级应用开发实践的工具集合,这些工具集以接口、抽象类、或工具类的形式存在于Sprin…

spring AOP 原理

一、spring注册 AnnotationAwareAspectJAutoProxyCreator 通过EnableAspectJAutoProxy可以看到先把AspectJAutoProxyRegistrar通过Import注册到spring。 AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口,所以就有了将某个bean引入spring 的能力…

Spring的AOP实现原理

本学习笔记将尽可能的将AOP的知识讲解的通俗易懂,先从一个典型的问题出发,引入AOP这个概念,介绍AOP的基本概念,再到Spring中的AOP的实现方案,最后进行一个简单的总结归纳。本学习笔记中不考虑cglib、也不会太关注Sprin…

spring的AOP和IOC的原理

目录 一、spring的ioc与aop原理 二、代理模式: 三、静态代理 四、动态代理 五、实际的操作 六、动态代理的实现: 七、什么是AOP 八、主流的AOP框架: 九、术语: 十、通知的五种类型: 十一、AOP的优点&#x…

spring aop原理

🍅 Java学习路线:搬砖工逆袭Java架构师 🍅 简介:Java领域优质创作者🏆、CSDN哪吒公众号作者✌ 、Java架构师奋斗者💪 🍅 扫描主页左侧二维码,加入群聊,一起学习、一起进步…

AOP原理

AOP原理 什么是AopAOP的作用AOP的基本概念AOP使用场景AOP原理如何动态修改功能AOP的编程思想AOP面向切面编程操作AOP通知执行的顺序代码执行流程准备工作源码揭开面纱 什么是Aop AOP(Aspect Orient Programming)也就是面向切面编程,作为面向对…

无法显示页面,因为发生内部服务器错误。

用iis添加网站后,访问域名,显示“无法显示页面,因为发生内部服务器错误。” 之前我将这些文件放在一个Demo文件夹中,把Demo放在test站点下,通过域名访问Demo报错。 我将Demo下的文件直接放在test下,访问成…

遇到“服务器内部错误http500怎么办?

出现500错误的原因是很多的,一般来说都是程序错误导致的,如果程序出错,那么在浏览器内会返回给用户一个友好的错误提示,统一称之为服务器500错误。 解决的方法就是您必须在http中能够正确的获得错误信息,方法为&#x…

500 - 内部服务器错误--解决方案

一般网上的方法是这样的: 一、打开 Internet 信息服务(IIS)管理器。点击出错的站点,并双击右边的ASP图标,如下图所示: 二、展开右侧配置中的“调试属性”,把“将错误发送到浏览器”的值设为 "true"&#xf…

HTTP状态 500 - 内部服务器错误 类型 异常报告,初学servlet遇到的问题

写给自己看,初学记录一下,maven项目中tomcat,Servlet遇到的问题 HTTP状态 500 - 内部服务器错误 类型 异常报告,初学servlet遇到的问题 类似这种报错,在hello world级别的servlet中碰到。 报错分析 大概是说自定义java类在实例…

IIS 配置网站出现500内部服务器错误,显示具体错误信息

1、打开IIS 找到如下图的部分,双击点开 2、点开之后找到如下图部分,点击 3、选择如下图部分,然后点击确定。 4、这个时候页面会出现详细的错误,如果没有出现详细错误,配置如下图部分,不勾选。 5、这时会出现…

Nextcloud 内部服务器错误解决

在部署nextcloud过程中最后登录页面时出现内部服务器错误,心态当时就炸了。 在网上找了各种方案,但是大部分博主都告诉我是/var/lib/php/session/属组的权限问题,或者web目录的权限不对。但是对我这个问题没有用。 我把他们的方案贴出来对你…

IDEA中HTTP500 - 内部服务器错误类型 在 [] 行处理 [/.jsp] 时发生异常情况;java.lang.NoSuchMethodError: com.Bean.Person.setId

问题: HTTP状态 500 - 内部服务器错误 类型 异常报告 消息 在 [65] 行处理 [/pages/el 5/elDataDemo2.jsp] 时发生异常 描述 服务器遇到一个意外的情况,阻止它完成请求。 例外情况 org.apache.jasper.JasperException: 在 [65] 行处理 [/pages/el 5/elDa…

HTTP状态 500 - 内部服务器错误:No converter found for return value of type: class xxx(简单分析及解决)

问题描述 以下内容基于ssm框架,当我们向tomcat服务器发起请求时,出现如下的错误状态提示–500。 Tomcat日志信息: 原因分析: 未找到类型返回值的转换器:类 com.ssm.utils.Msg,使用jackson绑定数据时出现…

阿里云服务器出错500 - 内部服务器错误

阿里云服务器部署并发布成功后,访问该网页时出错,报 500 - 内部服务器错误。 原因:1.http 500内部服务器错误说明IIS服务器无法解析ASP代码,如果你联网还发现找不到服务器就是500错误了. 2.在安装Framework v4.0之后&#xff0c…