Spring源码-学习随笔(一)AOP代理实现的切入口

2021/7/25 11:43:32

本文主要是介绍Spring源码-学习随笔(一)AOP代理实现的切入口,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

首先了解在没有Springboot的spring项目中,aop是如何启用的。

一、

  首先需要@EnableAspectJAutoProxy配合@Configuration 在spring中开启aop,所以起点在这个注解中,首先研究这个注解大概做了什么

 

重点在那个import的类中,从名字中可以猜出,是实现了接口,然后通过beanRegistrar将bean的定义信息注册到beanFactory中,然后等待创建

 

 

一开始,bean的定义信息中肯定没有internalAutoProxyCreator这个beanName,所以最终注册一个name是internalAutoProxyCreator的AnnotationAwareAspectJAutoProxyCreator的bean定义信息

这个就是这个注解的作用,用来注册一个ProxyCreator,从名字猜一下就是创建代理的。

二、

  接下来看看在springBoot中,AOP的入口在哪里。

  因为在springBoot中使用aop的时候,我们并不需要添加上述的那个注解,一般都是直接添加相应的starter依赖,然后就可以使用了,这涉及springboot的自动配置原理,有兴趣可以去了解,这里直接说结果。

我们在自动配置文件spring.factoryies中发现该类 EnableAutoConfiguration --> AopAutoConfiguration

 

从类中可以看到,只要存在类Advice,自动配置就会开启,然后可以发现,默认开启的代理模式是cglib的代理,在这里出现了@EnableAspectJAutoProxy注解,所以同样的,自动开启了AOP

然后还会发现,出现一个ClassProxyingConfiguration,也同样的会调用一个相似的方法来创建ProxyCreator

 

进去之后,发现最终调用的方法一样,但是参数不一致,但是在此时,因为@EnableAspectJAutoProxy注解,我们的ProxyCreator已经创建了,所以回顾上文的这个方法,我们会进入if中,将已经创建的ProxyCreator与我们希望创建的ProxyCreator比较优先级,决定最终容器中的ProxyCreator,也就是我们可以通过实现这个自定义的ProxyCreator来覆盖spring提供的默认ProxyCreator

三、

  那么入口知道了,我们开始研究一下AnnotationAwareAspectJAutoProxyCreator这个类,是如何在bean的创建过程中完成代理的。

首先看下这个类的继承树:

 

可以发现,这个类主要的代理功能肯定是在主干的抽象类中,然后我们还看到它还实现了BeanPostProcessor类型接口,这也就意味着,这个ProxyCreator的执行时机是在Bean的创建前后或者初始化前后。

接下来以此为切入口,继续分析整个继承树中,BeanPostProcessor接口的方法的实现在哪一层,进一步猜测这个类的执行时机。

 

查看之后可以看到,接口的实现集中在这个抽象类中,而且有作用的实现方法只有两个,以此得出,代理的创建时机只有两个地方,分别是bean实例化之前和bean初始化之后。

AbstractAutoProxyCreator --> postProcessBeforeInstantiation(InstantiationAwareBeanPostProcessor)
AbstractAutoProxyCreator --> postProcessAfterInitialization(BeanPostProcessor

AbstractAutoProxyCreator --> getEarlyBeanReference(SmartInstantiationAwareBeanPostProcessor)

 

 

 

然后我们可以简单看下,这个代理的创建过程,都是集中在createProxy方法中

 

createAopProxy

接着将创建的AopProxy调用getProxy

然后代理创建完毕。

四、

  接着,将在容器启动过程中,bean的创建过程中,分析aop的创建时机

无论是spring原生项目还是springboot构建的项目,最终bean的创建还是会回到AbstractApplicationContext --> refresh() 方法中

在普通的bean的创建之前,会把bean定义信息中是beanPostProcessor接口的都创建出来,我们之前通过@EnableAspectJAutoProxy注解注册在bean定义信息中的AnnotationAwareAspectJAutoProxyCreator也就会被创建了

然后就是将bean定义信息中,所有未创建的单例bean全部创建

 

在createBean方法中,出现第一个aop代理的入口,应用InstantiationAwareBeanPostProcessor的接口方法,在bean实例化之前,返回一个代理bean。

不过,在平时的应用中,我暂时还没碰见应用这个方法的场景,暂时不知道这个入口会在什么时候被触发

然后进入真正的bean的创建

在doCreateBean中,出现第二个aop代理的入口,该代码位于bean的实例化之后,初始化之前,在这里target会被提前暴露在一级缓存,并且提供的方法是

SmartInstantiationAwareBeanPostProcessor接口的实现方法。可以猜测,这里暴露之后,在target初始化setter依赖注入的时候,发生循环依赖时,对方在获取到一级缓存中的方法并获取target的时候,拿到的是aop代理,而不是target

bean实例化之后,赋值完成之后,会对bean初始化

在这里出现第三的aop代理的入口,应用的方法是BeanPostProcessor接口的方法,在对bean初始化完成之后,进行aop代理

 

五、

至此,目前发现的aop的入口有三处,分别是bean实例化之前,实例化之后和初始化赋值之前,以及初始化之后。

第一种情况的应用场景还没搞清楚,暂且不说;

第二种情况是在target出现循环依赖的情况下,提前暴露一个aop代理的创建方法,这样可以保证依赖的bean拿到的是代理而不是本体;

第三情况是我遇到最多的,而且我的代码中都是使用的构造器注入,而构造器注入是不会有循环依赖的情况的

以上内容只是简述了aop代理的原理和切入口,还有一些其他的细节没有详述,例如aop的增强器是如何获取的,如何和target包装在一起的,aop的入口是不是只有这三个入口等等。

如有錯漏,欢迎指正。



这篇关于Spring源码-学习随笔(一)AOP代理实现的切入口的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程