Spring-单例的循环依赖

  1. AbstractApplicationContext.refresh()方法中finishBeanFactoryInitialization(beanFactory)方法,是核心方法。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  2. 先在缓存中获得实例,调用getSingleton(beanName)方法,缓存中获取不到实例,则调用getSingleton(beanName, () -> {});方法
    在这里插入图片描述
    在这里插入图片描述
  3. 先在一级缓存中拿
    在这里插入图片描述
  4. 一级缓存中拿不到再在二级缓存中拿
    在这里插入图片描述
  5. 二级缓存中没有则在三级缓存中拿取,这里拿到的是ObjectFactory对象,这里调用BeanPostProcessor接口,获取提前暴露的bean实例,singletonObject并升级为二级缓存
    在这里插入图片描述
  6. 如果缓存中拿不到实例,则创建实例,调用beforeSingletonCreation(beanName);beanName存入singletonsCurrentlyCreation容器
    在这里插入图片描述
  7. 调用creatBean方法在这里插入图片描述
  8. 调用createBeanInstance(beanName, mbd, args), 无参构造函数实例化
    在这里插入图片描述
  9. addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); 设置三级缓存
    在这里插入图片描述
  10. ioc di 依赖注入 populateBean(beanName, mbd, instanceWrapper);,这里会触发依赖属性的getBean操作。
    在这里插入图片描述
  11. 实例化操作完成后调用afterSingletonCreation(beanName);方法,此方法把singletonsCurrentlyInCreation要删除该bean,表示实例化完成。
    在这里插入图片描述
  12. 最后调用addSingleton方法,存入一级缓存,删除二级、三级缓存。
    在这里插入图片描述

循环依赖步骤:

1、A 类无参构造函数实例化后,设置三级缓存
2、A 类populateBean 进行依赖注入,这里触发了B 类属性的getBean 操作
3、B 类无参构造函数实例化后,设置三级缓存
4、B 类populateBean 进行依赖注入,这里触发了A 类属性的getBean 操作
5、A 类之前正在实例化,singletonsCurrentlyInCreation 集合中有已经
有这个A 类了,三级缓存里面也有了,所以这时候是从三级缓存中拿到的提前暴露的
A 实例,该实例还没有进行B 类属性的依赖注入的,B 类属性为空。
6、B 类拿到了A 的提前暴露实例注入到A 类属性中了
7、B 类实例化已经完成,B 类的实例化是由A 类实例化中B 属性的依赖注入触发
的getBean 操作进行的,现在B 已经实例化,所以A 类中B 属性就可以完成依赖注
入了,这时候A 类B 属性已经有值了
8、B 类A 属性指向的就是A 类实例堆空间,所以这时候B 类A 属性也会有值了。

--------------------------

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

面试官:“为什么要使用三级缓存呢?二级缓存能解决循环依赖吗?”

答:如果要使用二级缓存解决循环依赖,意味着所有Bean在实例化后就要完成AOP代理,这样违背了Spring设计的原则,Spring在设计之初就是通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器来在Bean生命周期的最后一步来完成AOP代理,而不是在实例化后就立马进行AOP代理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值