如题,该篇博文主要是对Spring初始化后AOP部分代码执行流程的分析,仅仅只是粗略的讲解整个执行流程,喜欢细的小伙伴请结合其他资料进行学习。

在看本文之前请一定要有动态代理的基础,否则后后半部分内容就像是坐牢,因为我写的比较简略。如果对动态代理不熟悉的小伙伴,可以参考我之前的博客:浅谈Cglib、Jdk以及ProxyFactory实现动态代理上的区别,两篇结合着看。

可以这么说,在明白了Cglib、Jdk动态代理以及使用ProxyFactory实现动态代理的基础上,Spring的AOP后半部分的代码,大致的执行骨架就明白了。

废话不多说,往下学吧,祝你好运!

文章目录

  • 一、AOP代码结构大纲
  • 二、核心类AnnotationAwareAspectJAutoProxyCreator
    • 1、AbstractAutoProxyCreator抽象类
    • 2、@EnableAspectJAutoProxy
  • 三、找到当前Bean的所有切入点
    • 1、调用findCandidateAdvisors方法
    • 2、调用父类的findCandidateAdvisors方法
    • 3、调用buildAspectJAdvisors方法
  • 四、找到当前Bean的符合要求的切入点
    • 1、方法一直跳转,最终调用的就是canApply方法
    • 2、获取匹配的切入点match
    • 3、最终将符合要求的Advisor添加到集合返回
  • 五、对切入点进行排序
  • 六、构建所有的Advisor
    • 1、创建ProxyFactory对象
    • 2、添加符合Bean的所有切入点
    • 3、调用具体的动态代理实现方式
  • 七、Cglib动态代理执行逻辑
  • 八、Jdk动态代理执行逻辑
    • 1、调用getProxy方法
    • 2、执行this指向类的invoke方法
    • 3、构建Advisor执行链
    • 4、proceed执行代理逻辑

一、AOP代码结构大纲

由于该部分代码涉及的细节过多,这里就不一一讲解,更多的是讲明白每一部分是干嘛的,以及大致是如何干的,最主要的是理清楚该部分代码的逻辑。

该部分代码的大致执行逻辑整理为了对应的执行流程图:

我将代码逻辑分为六部分:

1、方法入口

2、找到当前Bean的所有切入点

3、在当前Bean的所有切入点中找到符合要求的切入点

4、对切入点进行排序

5、将我们前面找到的所有切入点封装为Advisor数组

6、根据Advisor数组执行Cglib动态代理逻辑

7、根据Advisor数组执行Jdk动态代理逻辑


二、核心类AnnotationAwareAspectJAutoProxyCreator

1、AbstractAutoProxyCreator抽象类

正常情况下AOP功能的代码实现,是在Bean的生命周期初始化后进行调用。

初始化后会进行所有的初始化后的postProcess,此时就会调用到AbstractAutoProxyCreator类(实现了BeanPostProcessor接口)的postProcessAfterInitialization方法,即开始我们的AOP之旅。

一定一定要明白,这是Bean的生命周期,即每一个Bean都会执行这一步,所以这里的概念都是站在Bean的基础上进行讲解的!!!

即AOP的入口为AbstractAutoProxyCreator类的postProcessAfterInitialization方法

2、@EnableAspectJAutoProxy

如果你足够细心,你就会发现,Spring中的AOP是一个可插拔的功能。Spring天然是不具备AOP功能的,如果使用注解的方式进行配置,我们需要在配置类上添加一个@EnableAspectJAutoProxy注解,也就是这个注解让我们的Spring拥有了AOP的功能。

接下来让我们简单看看这个注解干了什么。

1)Import一个类(第一张图)

了解Spring容器启动流程的小伙伴就应该知道,该功能就是向Spring容器中添加一个Bean。

Import注解解析的位置在我们解析Configuration配置类的时候就会进行解析。

想了解具体解析位置的小伙伴可以参考该篇博客的第四步,即第二张图的位置:Spring解析@ComponentScan注解的执行流程


2)在解析Import注解的时候,会调用对应的registerBeanDefinitions方法,即又注册了一个Bean,这个Bean就是AnnotationAwareAspectJAutoProxyCreator.class这个类

3)为什么注入的是AnnotationAwareAspectJAutoProxyCreator这个类,但是调用AOP的方法确实AbstractAutoProxyCreator这个类呢?

因为它们是继承关系。


三、找到当前Bean的所有切入点

简单的代码直接略过,最终会进入到wrapIfNecessary方法内部。

然后执行getAdvicesAndAdvisorsForBean方法,内部分成三步,即三、四、五

再执行createProxy方法,内部也分为三步,即六、七、八

1、调用findCandidateAdvisors方法

getAdvicesAndAdvisorsForBean该方法在当前类是一个接口,然后由子类实现,然后又会调用findEligibleAdvisors方法,最终执行我们该节的目标方法findCandidateAdvisors

2、调用父类的findCandidateAdvisors方法

最终调用findAdvisorBeans方法

该方法功能为解析我们自己新建类,然后自定义的advisor的切入点

1)根据Bean的类型去Spring容器中找我们的Bean,即如果我们编写一个类实现了这个接口Advisor接口,就会被认为是一个切入点

2)过滤掉一些和循环依赖创建有关的Advisor的Beaen

3)至此,我们自定义的Advisor就被找到了

这种就是实现了Advisor接口的Bean

3、调用buildAspectJAdvisors方法

然后执行aspectJAdvisorsBuilder.buildAspectJAdvisors()方法。这个方法很暴力,也很深

1)同样的还是根据类型,此时的类型是Object,即拿到所有的Bean。然后解析类上是否有@Aspect注解

2)将注解包装成一个AspectMetadata类,然后解析类上的一些信息

3)关键就是这个getAdvisors方法

该步为获取所有使用@Aspect类中的所有切入点

4)最终会将所有的切入点实例化为InstantiationModelAwarePointcutAdvisorImpl对象,该对象内部就含有对不同@After、@Before注解的解析

5)理解InstantiationModelAwarePointcutAdvisorImpl类对于后面的解析有帮助

这里调用的是AspectJAdvisorFactory接口的getAdvice方法,ReflectiveAspectJAdvisorFactory类又是该接口的实现,所以就调用到了ReflectiveAspectJAdvisorFactory类的getAdvice方法


四、找到当前Bean的符合要求的切入点

前面已经到了所有的切入点,现在就是要找到符合当前Bean的切入点

方法的入口是findAdvisorsThatCanApply

1、方法一直跳转,最终调用的就是canApply方法

2、获取匹配的切入点match

前面文章开头有说过,请务必了解三种动态代理的不同实现方式,这里调用match方法(后面有图),就可以理解为进行方法参数和方法名称的匹配

就在刚刚过去的第三节,第三点的,第五步,每一个切入点最终都会封装为一个InstantiationModelAwarePointcutAdvisorImpl类的对象,最终调用getAdvice方法,就会进行方法的解析。这个是不是就和使用Proxyfactory实现动态代理的长相一模一样,我们在使用Proxyfactory实现动态代理的时候,也是调用getAdvice方法获取对应的代理逻辑

3、最终将符合要求的Advisor添加到集合返回


五、对切入点进行排序

调用sortAdvisors方法,对符合当前Bean要求的Advisor进行排序,我们所熟知的Order就是在这个位置进行解析

该方法会对每一个Advisor创建一个比较器,然后排序,再依次放入集合中


六、构建所有的Advisor

如果还不明白我文章开头所说的三种实现动态代理的方式的,一定要看,不然你就看不懂后面的代码了,我在讲解该部分的时候就默认你是懂的动态代理的。

浅谈Cglib、Jdk以及ProxyFactory实现动态代理上的区别

1、创建ProxyFactory对象

2、添加符合Bean的所有切入点

其实该方法不用细看,结合ProxyFactory,你就明白它是在添加前面是已经排好序了的切入点

3、调用具体的动态代理实现方式

这里就分为Cglib和Jdk两种形式

Spring会根据我们当前Bean的基本情况进行选择,到底使用那种动态代理的实现方式。这里就出现了我们所说的使用Jdk动态代理的类必须要实现接口


七、Cglib动态代理执行逻辑

会使用Cglib动态代理是基础

1、创建Enhancer对象

2、添加对应的superClass属性

3、添加callbackFilter属性

4、添加其他属性

3、添加callbacks属性

4、调用create方法,执行代理流程


八、Jdk动态代理执行逻辑

会使用Jdk动态代理是基础

1、调用getProxy方法

2、执行this指向类的invoke方法

正常我们使用Jdk动态代理的时候,第三个位置都是传入一个InvocationHandler,此处的InvocationHandler指向的是this,即执行当前类的invoke方法

3、构建Advisor执行链

该步骤不像Cglib一样,直接添加对应的属性就能够使用,而是需要自己构建对应的Advisor执行链,可以理解为最终的执行逻辑使用了责任链设计模式

此步骤仅完成Advisor的链条构建,没有真正的去执行对应的代理逻辑

4、proceed执行代理逻辑

根据Advisor执行链条执行代理逻辑,然后调用invokeJoinpoint方法执行对应的被代理的逻辑。

个人认为该类设计的十分巧妙,利用递归和Advisor的数量以及构建好的执行链完成整个的代理逻辑,秒呀,值得好好研究学习!!!

浅谈SpringAOP功能源码执行逻辑相关推荐

  1. 2023-01-18 ClickHouse之聚合功能源码分析

    前言 聚合分析是从海量数据中提取数据的基本方法,对于OLAP数据库而言,聚合分析是其关键能力之一,ClickHouse在这方面也做了很多设计和优化,正如ClickHouse在文档中所述: 本文将分析展 ...

  2. android 距离传感器 api,Android传感器API之:近距离感应Proximity功能源码

    并不是所有Android手机上都保留有距离感应器.基于这个感应器可以有一些很不错的小应用,比如近距离感应锁屏.解锁-- 分享Rexsee的距离感应功能源码,回头可以自个儿做..更多的传感器API我这几 ...

  3. android 加速度模块,Android传感器API之:加速度Accelerometer功能源码

    已结贴√ 问题点数:20 回复次数:7 Android传感器API之:加速度Accelerometer功能源码 加速度传感器,主要是感应手机的运动.捕获三个参数,分别表示空间坐标系中X.Y.Z轴方向上 ...

  4. 使用php实现自动获取一个获取文章标题生成主题关键词功能源码

    使用php实现自动获取一个获取文章标题生成主题关键词功能源码 功能展示 1.根据你文章标题,自动获得百度下拉等长尾词生成页面 2.没有后台 生成的页面可以通过js控制所有页面的广告 3.轻量级辅助插件 ...

  5. 利用JS调用手机摄像头小功能源码

    介绍: 一个小功能源码,利用JS调用手机摄像头,当访问网址后就能拍摄照片,前提是客户端给了权限. 1.由于系统安全机制,ios系统必须使用自带的Safari浏览器(或者第三方APP调用的是Safari ...

  6. 微信小程序做留言板mysql_微信小程序留言板功能源码

    微信小程序留言板功能源码?先说一下 1.到微信公众平台下载开发者工具.安装 2.appID与没有appID的区别是,appID可以用真机预览,而没有就不行 3.目录解释: a)pages放页面,每个都 ...

  7. 简易影视小程序v1.0.1版本新增过审功能源码

    v1.0.1版本更新日志 1.增加激励广告 2.增加插屏广告 3.增加视频贴片广告 4.增加原生广告 5.独立tk框架后台,简易操作 6.增加小程序过审核功能,后台自定义审核页面 7.增加自定义多接口 ...

  8. 浅谈自媒体带货底层逻辑及公众号变现操作路径

    随着自媒体行业的繁荣,带货成为最近两年品牌圈的热门词汇.当品牌选择一个博主时,带货能力强不强是一个至关重要的标准. 正如备受追捧的淘宝大主播李佳琦.薇娅,品牌商家看重的也是他们强大的带货能力. 本文将 ...

  9. 浅谈Linux磁盘存储管理续【逻辑卷管理(LVM)】

    一.LVM的基本概念 在对磁盘进行分区大小规划时,有时往往不能确定这个分区要使用的总空间大小,而用fdisk对磁盘分区后,每个分区的大小已经固定了,如果分区设置的过大,就白白浪费了磁盘空间,而分区设置 ...

  10. 浅谈spring--AOP与IOC / DI

    Spring 是一个开源框架,主要优势是其分层架构,分层架构允许选择使用哪一个组件. 七大模块组成包含Spring Core,AOP,ORM,DAO,Web,Context,Web MVC. Spri ...

最新文章

  1. python slice是共享内存吗_在共享内存中使用numpy数组进行多处理
  2. 微信创始人张小龙的创业故事
  3. 音乐游戏 简单模拟,字符串,cin.get,getchar,流同步(女赛)
  4. Firefox 技巧
  5. 大数据_Flink_流式处理_简介_认识一下什么是BI中的ETL---Flink工作笔记0005
  6. Axure RP 9 for Mac(原型设计软件)
  7. 犯贱报(一张浓缩大学生活的..)
  8. 对数log、lg、ln
  9. 通过UA判断手机的类型
  10. matlab 中gradient()函数的用法
  11. 小程序之botton默认带边框的问题
  12. uniapp网易严选项目
  13. 毕业设计总结(惯性导航)
  14. 微信发红包、QQ登录、搜索框、水杯、聊天窗口、两台电梯、微信/淘宝支付、笔、 抖音发布短视频等功能测试用例
  15. Python改变图片像素值
  16. 近红外光谱预测苹果糖度
  17. CH5202 自然数拆分Lunatic版【完全背包】
  18. idea中没有 program arguments 选项
  19. jQuery整理笔记七----几个经典表单应用 .
  20. 画星c语言程序,用星号画了一个正五角星。

热门文章

  1. Luogu1880 石子合并
  2. webpack5学习与实战-(五)-直接加载资源
  3. js高级学习笔记(b站尚硅谷)-11-变量提升与函数提升
  4. 解决源码安装手册找不到问题
  5. time 测试一条命令的执行时间
  6. android系统的图标大小,android开发中手机图标大小的问题
  7. 电脑中的打印驱动程序如何打包_旧驱动程序会教您如何处理笔记本电脑上的黑屏...
  8. java中复制图片_2017.5.3 java中 复制图片的4种方式(copy图片只能用字节流对象)...
  9. reduce python3_Python3的高阶函数:map,reduce,filter
  10. Introduction to Computer Networking学习笔记(十九):rate guarantees交换速度保证