Spring如何解决单例Bean出现的循环依赖问题(非构造器注入)

spring每次在创建对象之前都是先从容器里查找该bean对象是否存在,getBean(beanName),不存在才会创建doGetBean。

假设A、B两个对象相互依赖:
spring初始化流程:从DefaultListableBeanFactory 方法 getBean(beanName) 进入——>doGetBean——>getSingleton(beanName)
——>getSingleton(beanName,lambda),lambda内部调用createBean——> doCreateBean——>createBeanInstance——>addSingletonFactory(添加bean早期对象到三级缓存)——>populateBean——>initializeBean
注意getSingleton(beanName)与getSingleton(String beanName, ObjectFactory<?> singletonFactory)是DefaultSingletonBeanRegistry的重载方法,后者内部会执行createBean方法。

①、A实例化
在第一次实例化前getBean会调用getSingleton判断缓存中是否存在A,不存在且A是单例Bean,调用getSingleton(beanName,lambda),lambda中会执行createBean方法开始创建A,通过doCreateBean调用createBeanInstance完成A的实例化。(此时是未完成初始化的A)
同时通过addSingletonFactory方法将A的早期对象添加到三级缓存中,此时的key是对象名,value是一个lambda表达式addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));。

②、A属性填充
完成实例化后,对A进行属性填充,调用populateBean方法populateBean(beanName, mbd, instanceWrapper);此时将对A中的属性B进行设置
populateBean调用applyPropertyValues方法根据属性名称设置值时,会调用resolveValueIfNecessary方法判断value是不是RuntimeBeanReference(引用类型),如果是,此时会调用resolveReference()方法进行B引用的解析和自动装配。在resolveReference()方法中通过 bean = this.beanFactory.getBean(refName);进行B对象的初始化流程,这里的beanFactory是AbstractBeanFactory的对象。

③、实例化、初始化B
和A实例化一样,此时缓存也没有B对象,执行相同的流程。当B的早期对象添加进三级缓存后,调用populateBean进行属性设置,此时B依赖A,所以会对A进行设置。同一样会经过resolveValueIfNecessary判断是否为引用类型,再次进入获取对象A的流程getSingleton(beanName),此时可以在三级缓存中根据A的名称获取name所对应的早期对象,通过方法getEarlyBeanReference获取A对象,再把拿到的A对象put到二级缓存earlySingletonObjects中,同时删除三级缓存。A属性设置完成后,调用initializeBean方法完成B的初始化操作。此时lambda表达式中create方法的流程执行完毕,B初始化完成,继续执行getSingleton(String beanName, ObjectFactory<?> singletonFactory)后面的逻辑,调用addSingleton(beanName, singletonObject);方法,将B添加到一级缓存并清除B的二级、三级缓存。

④、初始化A
完成B初始化后,resolveValueIfNecessary方法已经得到了一个完整的B对象,会接着上面2后面的流程给A设置B属性。然后调用initializeBean方法完成A的初始化操作。和3一样,调用addSingleton(beanName, singletonObject);方法,将A添加到一级缓存并清除A的二级、三级缓存。

方法说明:
1)、addSingletonFactory,是完成实例化bean后紧接着调用的,作用是向三级缓存中添加尚未初始化的bean(只是分配了内存地址);
2)、getSingleton(String beanName, ObjectFactory<?> singletonFactory),判断缓存中是否存在该bean,标记正在创建的bean(调用isSingletonCurrentlyInCreation方法向singletonsCurrentlyInCreation列表添加正在创建的bean),singletonFactory创建bean的工厂,可传入lambda表达式;
3)、getSingleton(String beanName),判断缓存中是否存在该bean,且bean是否正在创建(通过isSingletonCurrentlyInCreation方法判断singletonsCurrentlyInCreation集合里是否包含bean名称)。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值