首页 > 编程语言 >浅谈SpringAOP功能源码执行逻辑

浅谈SpringAOP功能源码执行逻辑

时间:2023-01-19 11:08:18浏览次数:52  
标签:调用 浅谈 切入点 代理 Bean 源码 Advisor SpringAOP 方法


如题,该篇博文主要是对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代码结构大纲

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

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

浅谈SpringAOP功能源码执行逻辑_动态代理


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

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的基础上进行讲解的!!!

浅谈SpringAOP功能源码执行逻辑_AOP_02


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

浅谈SpringAOP功能源码执行逻辑_AOP_03


2、@EnableAspectJAutoProxy

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

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

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

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

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

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

浅谈SpringAOP功能源码执行逻辑_spring_04


浅谈SpringAOP功能源码执行逻辑_spring_05


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

浅谈SpringAOP功能源码执行逻辑_动态代理_06


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

因为它们是继承关系。

浅谈SpringAOP功能源码执行逻辑_spring_07



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

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

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

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



1、调用findCandidateAdvisors方法

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

浅谈SpringAOP功能源码执行逻辑_初始化_08


2、调用父类的findCandidateAdvisors方法

最终调用findAdvisorBeans方法

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

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

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

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

浅谈SpringAOP功能源码执行逻辑_初始化_09



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

浅谈SpringAOP功能源码执行逻辑_动态代理_10


3、调用buildAspectJAdvisors方法

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


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

浅谈SpringAOP功能源码执行逻辑_初始化_11


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

浅谈SpringAOP功能源码执行逻辑_AOP_12


3)关键就是这个getAdvisors方法

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

浅谈SpringAOP功能源码执行逻辑_AOP_13


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

浅谈SpringAOP功能源码执行逻辑_动态代理_14


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

浅谈SpringAOP功能源码执行逻辑_AOP_15



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

浅谈SpringAOP功能源码执行逻辑_spring_16



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

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

方法的入口是findAdvisorsThatCanApply



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

浅谈SpringAOP功能源码执行逻辑_AOP_17



2、获取匹配的切入点match

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

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

浅谈SpringAOP功能源码执行逻辑_spring_18

浅谈SpringAOP功能源码执行逻辑_动态代理_19


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

浅谈SpringAOP功能源码执行逻辑_动态代理_20



五、对切入点进行排序

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



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

浅谈SpringAOP功能源码执行逻辑_AOP_21



六、构建所有的Advisor

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

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



1、创建ProxyFactory对象

浅谈SpringAOP功能源码执行逻辑_动态代理_22


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

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

浅谈SpringAOP功能源码执行逻辑_spring_23


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

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

浅谈SpringAOP功能源码执行逻辑_初始化_24


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

浅谈SpringAOP功能源码执行逻辑_AOP_25



七、Cglib动态代理执行逻辑

会使用Cglib动态代理是基础

1、创建Enhancer对象

2、添加对应的superClass属性

3、添加callbackFilter属性

4、添加其他属性

3、添加callbacks属性

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

浅谈SpringAOP功能源码执行逻辑_spring_26



八、Jdk动态代理执行逻辑

会使用Jdk动态代理是基础

1、调用getProxy方法

浅谈SpringAOP功能源码执行逻辑_初始化_27


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

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

浅谈SpringAOP功能源码执行逻辑_spring_28


3、构建Advisor执行链

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

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

浅谈SpringAOP功能源码执行逻辑_spring_29


4、proceed执行代理逻辑

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

浅谈SpringAOP功能源码执行逻辑_spring_30

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


标签:调用,浅谈,切入点,代理,Bean,源码,Advisor,SpringAOP,方法
From: https://blog.51cto.com/u_15942107/6019925

相关文章

  • 浅谈使用实现FactoryBean接口的方式定义Bean
    在定义一个Bean的时候,我们可以直接实现FactoryBean接口,然后重写对应的getXxx方法,就能够完成一个Bean的定义工作文章目录​​一、使用实现接口的方式定义Bean​​​​二、其......
  • 浅谈Spring如何利用三个缓存Map解决循环依赖
    写在最前面,在写这篇文章之前,我也参考了很多别人对于Spring循环依赖的讲解,大部分人都是按照先使用二级缓存,再使用三级缓存的思路去讲解。在阅读了Spring源码中关于循环依赖的......
  • 浅谈BeanDefinition、BeanDefinitionMap、RootBeanDefintion三者的关系
    文章目录​​一、BeanDefinition​​​​1、具体实现子类​​​​2、手动创建子类​​​​3、beanClass成员变量的含义​​​​二、BeanDefinitionMap​​​​三、RootBeanD......
  • 浅谈InnoDB存储引擎的MVCC机制
    文章目录​​一、数据库事务隔离级别​​​​1、事务原则​​​​2、4种隔离级别​​​​3、会出现的3种问题​​​​二、MVCC概念​​​​1、基本结构​​​​2、字段介绍......
  • 浅谈Spring中Bean的生命周期
    文章目录​​1、基本概念​​​​2、生命周期流程图​​​​3、源码与功能分析​​​​3.1、实例化前​​​​3.2、实例化​​​​3.3、实例化后​​​​3.4、初始化前前​......
  • SpringBoot源码学习3——SpringBoot启动流程
    系列文章目录和关于我一丶前言在《SpringBoot源码学习1——SpringBoot自动装配源码解析+Spring如何处理配置类的》中我们学习了SpringBoot自动装配如何实现的,在《Sprin......
  • 浅谈Netty中ServerBootstrap服务端源码(含bind全流程)
    文章目录​​一、梳理Java中NIO代码​​​​二、Netty服务端代码​​​​1、newNioEventLoopGroup()​​​​2、group​​​​3、channel​​​​4、NioServerSocketChanne......
  • 浅谈Redisson底层源码
    Redisson源码分析​​一、加锁时使用lua表达式,执行添加key并设置过期时间​​​​二、加锁成功之后给锁添加对应的事件​​​​三、加锁完成,看门狗自动续命未处理完的线程​......
  • drf快速使用 CBV源码分析 drf之APIView分析 drf之Request对象分析
     目录序列化和反序列化drf介绍和安装使用原生django写接口djangoDRF安装drf快速使用模型序列化类视图路由datagrip使用postman测试接口CBV源码分......
  • 浅谈三种使用Redis实现MQ的方式
    文章目录​​一、消息队列​​​​二、基于List的消息队列​​​​三、基于PubSub的消息队列​​​​四、基于Stream的消息队列​​​​1、基本命令​​​​2、简单使用​​......