Spring的循环依赖

1、两个类相互引用

2、三级缓存可以解决循环依赖

(字段注入、setter注入、构造器注入的对象无法解决循环依赖

3、Spring的生命周期(创建大概流程)

BeanDefinition的读取阶段:我们在往Spring容器注入Bean的时候,一般会通过比如xml方式,@Bean注解的方式,@Component注解的方式,其实不论哪一种,容器启动的时候都会去解析这些配置,然后为每个Bean生成一个对应的BeanDefinition,这个BeanDefinition包含了这个Bean的创建的信息,Spring就是根据BeanDefinition去决定如何创建一个符合你要求的Bean
Bean的实例化阶段:这个阶段主要是将你配置的Bean根据Class的类型创建一个对象出来
Bean的属性赋值阶段:这个阶段主要是用来处理属性的赋值,比如@Autowired注解的生效就是在这个阶段的
Bean的初始化阶段:这个阶段主要是回调一些方法,比如你的类实现了InitializingBean接口,那么就会回调afterPropertiesSet方法,同时动态代理其实也是在这个阶段完成的。

4、哪三级缓存

第一级缓存:singletonObjects 存放已经完全创建好的bean

第二级缓存:earlySingletonObjects 

第三级缓存:singletonFactories 存的是每个Bean对应的ObjectFactory对象,通过调用这个对象的getObject方法,就可以获取到早期暴露出去的Bean。

单例bean通过三级缓存解决循环依赖,多例bean无法解决!!!

5、获取bean

org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String)

bean实例化结束后,会先把bean放入第三级缓存

  6、三级缓存解决流程

项目启动,先创建A, 构建一个ObjectFactory对象放到三级缓存,依赖注入时,处理@Autowired修饰的B,去找B对象,二级缓存和三级缓存都么有,所以会去创建B对象,A对象的注入过程就暂停了,先实例化B,然后一样,构建一个ObjectFactory对象放到三级缓存,然后依赖注入,处理@Autowired修饰的A,查找A,查一级缓存、二级缓存没有,三级缓存有,掉三级缓存的getObject方法,获取到早期A,放到二级缓存(如果有其他循环依赖,可直接从二级依赖获取早期对象),删除三级缓存,虽然是早期的A对象,但是与完整的A对象是同一个。此时B对象的依赖注入完成,再经过其他阶段的处理,B对象创建完成,放入一级缓存,清空二三级缓存,再继续A对B的依赖注入,以及后续流程。

 7、构造器注入无法解决循环依赖

三级缓存为什么不能解决循环依赖?

因为,A对象实例化结束后,才会放入三级缓存,发生循环依赖时,可通过三级缓存ObjectFactory.getObject()获取到早期A对象;

但是构造器注入发生在实例化时,此时A对象还没有实例化完成,不会放入三级缓存,那么创建B对象时,就不会从三级缓存中获取到早期A对象,那么就要去创建A,但是A正在创建,就会报错!

8、多例对象无法解决循环依赖

9、aop的代理对象的创建流程

假设有代理对象A需要创建,首先创建原型对象A,在创建原型对象前,有就会通过SmartInstantiationAwareBeanPostProcessor的前置处理器创建代理对象来代替原型对象A。

 但是由于这里TargetSource=null,所以没有创建出代理对象

 后续在BeanPostProcessor的后置处理器,生成代理对象。

 AbstractAutoProxyCreator:

 创建完成后,放入一级缓存,供后续getBean使用

10、代理对象A和无代理B的循环依赖

先创建代理对象A,实例化原型A后放入三级缓存,再依赖注入B,去实例化B,放入第三级缓存,再依赖注入A,去获取A,A存在第三级缓存中,所以调用三级缓存的singletonFactory.getObeject()方法获取到代理A,并放入二级缓存中。

 

获取代理对象

到这里,代理A的属性B的依赖注入完成了,继续代理A的创建。

因为上面原型A创建完成了,继续后面流程,

在处理BeanPostProcessor(AbstractAutoProxyCreator)的后置处理器时,由于之前处理循环依赖时,已经创建了代理A了,所以这里不需要再重复创建。

 在初始化结束后,会获取缓存,发现二级缓存里有代理A,所以这里将代理A替换原型A

11、为什么使用三级缓存而不是二级缓存

三级缓存ObjectFactory的getBean()方法获取到的bean可能是两种类型,一是实例化阶段创建出的对象,二是代理对象。

如果舍弃二级缓存,那么如果是代理对象,每次都会重新生成一个新的代理对象;

如果舍弃三级缓存,提前暴露代理对象,依赖注入的可能跟最后创建好的不一样;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值