Spring IOC学习笔记之bean的生命周期中的循环依赖

本篇笔记为上一篇《Spring IOC学习笔记之bean的生命周期》中的第5步的验证。

第5步:如果有循环依赖的情况,则提前暴露一个bean工厂,放到二级缓存中

首先介绍一下spring的三个缓存:

singletonObjects:springBean的单例池,一般称为一级缓存。

singletonFactories:单例工厂的缓存池,一般称为二级缓存。

earlySingletonObjects:未完成属性注入的对象,(一般是由单例工厂生成对象后放入其中)

/** Cache of singleton objects: bean name to bean instance. */
//单例对象的缓存池,key为beanName,value为bean实例
private final Map singletonObjects = new ConcurrentHashMap<>(256);

/** Cache of singleton factories: bean name to ObjectFactory. */
// 单例工厂的缓存池,key为beanName,value为bean工厂
private final Map> singletonFactories = new HashMap<>(16);

/** Cache of early singleton objects: bean name to bean instance. */
//早期单例对象的缓存池,key为beanName,value为反射创建出来的对象的实例(还为完成属性注入)
private final Map earlySingletonObjects = new HashMap<>(16);

/** Set of registered singletons, containing the bean names in registration order. */
// 存放已经注册(实例化)了的单例对象的beanName。
private final Set registeredSingletons = new LinkedHashSet<>(256);

开始测试:

修改测试代码:在TestB类中依赖注入TestA,TestA类中依赖注入TestB。

找到doCreateBean方法断点:

可以看到此时testA中还没有注入testB

从截图中可以看到earlySingletonExposure的值为true,存在循环依赖。

进入if语句执行addSingletonFactory:

进入方法查看:

 

可以看到在singletonFactories集合中放入一个key为teatA的单例工厂singletonFactory,这个singletonFactory对象中包含了一个TestA对象,但是这个TestA对象中的xxB的值为null,说明还没有注入TestB。

跳出addSingletonFactor方法:

执行到完成属性注入的populateBean方法:

当执行到AutowiredAnnotationBeanPostProcessor这个后置处理器的时候:

进入这个后置处理器查看:

发现这个TestA中需要注入一个TestB

调用inject方法进行注入:

此时要为TestA注入一个TestB,但是现在还没有TestB:

查看调用链,此时是在postProcessPropertiesfang方法中调用inject

进入inject方法:

调用了另一个inject方法(这两个方法只是名称相同,并不是同一个)

进入这个inject方法:

此时要为testA注入一个名称为xxB,类型为com.salulu.test.TestB的值。

调用resolveDependency方法:

resolveDependency方法中调用doResolveDependency方法

此时spring是要为testA这个bean,注入一个名为testB的bean,执行descriptor.resolveCandidate(autowiredBeanName, type, this)方法:

可以看到Spring要去beanFactory中获取名称为testB的bean,(创建testA这个bean,需要依赖testB,所以现在要去获取testB这个bean)

进入getBean方法:

调用了doGetBean(),这个方法很熟悉,之前创建testA的时候就是调用了doGetBean这个方法:

查看调用栈:

但是testB是获取不到的,因为现在还在创建testA的过程中,所以要创建testB:

再次进入doGetBean方法:

此时testA对象和testB对象都已经创建,但是两个对象都还没有完成依赖注入:

进入addSingletonFactory方法:

回想一下,之前创建testA的时候,也进入过这个方法,并且把testA的单例工厂对象放到了singletonFactories这个集合中:

下面要对testB进行属性注入:

已知testB依赖了testA,但是testA还在创建过程中

进入populateBean方法:

运行到要调用AutowirrtAnnotationBeanPostProcessor类的后置处理器:

进入这个后置处理器方法:

这个方法有点眼熟,因为之前为testA注入属性的时候也调用到了这里

继续往下执行:

需要在testB中注入testA,但是现在testA还在创建过程中:

看调用链:

在第一次调用doGetBean("testA")之后,经过和很多步骤:要实例化testB,testB也要进行依赖注入

继续往下看,会不会无限循环了呢,因为现在调用到了testB中要注入testA,但是现在是testA的创建过程中,会不会再去创建一遍testA呢??

这里中间的几步都是与之前的过程都是重复的,这里就不截图了,直接到getSingleton方法:

inject方法要为testB设置一个值为的testA属性,需要到单例池中取

现在要去单例池中获取testA,但是testA不在单例池中

但是可以从二级缓存singletonFactories中获取到一个testA的单例工厂,所以并没有死循环。

单例工厂中有testA对象

注意getSingleton方法中的这两行代码:

this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);

把testA从单例工厂池中移除,放入earlySingletonObjects这个三级缓存中(主要作用就是性能优化)

因为获取到了testA,此时调用field.set(bean,value),为testB注入testA

此时testB将要返回,回到testA的依赖注入过程:

testB已经返回,testA中也可以注入testB

到此,解决了循环依赖。

 

 

 

 

 

 

你可能感兴趣的:(spring,java,spring,bean,ioc,后端)