spring官网讲解的循环依赖问题
查看spring官网,它是这么介绍循环依赖的问题的
重点内容有:
在使用构造函数注入实例时,spring ioc会抛出bean在创建的错误
我们可以写一个例子来证明:
serviceA/B, 都使用了构造方法将对方注入自己的类中
clientConstructor:
就会形成一种无穷尽的依赖关系,在()里需要一直写service对象。所以说使用构造方法是没办法解决循环依赖的问题的,spring官网推荐我们使用setter方法,下面我们再来尝试一下:
serviceA/B
clientConstructor中,我们其实是使用了无参构造方法
运行结果:
结论:我们AB循环依赖问题只要A的注入方式是setter且是singleton,就不会有循环依赖问题
接下来我们再结合spring 容器IOC进行测试,单例和多例的区别
在配置文件中,我们需要定义bean的ID和参数
我们将默认的scope为singleton改成了prototype之后,会报这么一个错误
所以说spring的循环依赖只是在解决单例的问题,不解决多例,为什么呢?
spring是如何解决循环依赖的问题呢?运用的是哪三级缓存呢?
首先我们需要记住一个class类,这个类是源码查看三级缓存的类:defaultSingletonBeanRegistry
由图可知:解决循环依赖的三个缓存有:singletonObjects、singletonFactories、earlySingletonObjects ,仔细观察可以发现三个都是Map,value值分别是Object 、 ObjectFactories
其中这里注解一下三级缓存的概念:
singletonObjects :一级缓存,也叫做单例池,存放已经经历了完整生命周期的bean对象--------放成品的
earlySingletonObjects: 二级缓存,存放早期暴露出来的bean对象,bean的生命周期未结束(属性还未填充完整)----------放半成品的
singletonFactories :三级缓存,存放可以生成Bean的工厂,准备来构建对象的------准备生产的
一级和二级的Map的value都是Object类型,只有三级缓存是ObjectFactory类型
实例化和初始化:
实例化:内存中申请一块内存,通俗的话来说,就是先买了一套刚刚建好的房子,里面什么都没有,也就是毛坯房。
初始化:初始属性填充。通俗的话来说,给房子装修,将家居搬进去
循环依赖的三个Map和四个方法
先从一级缓存的singletonObjects里面拿对象,发现拿不到,就开始准备创建doCreateBean,创建好了之后就准备属性填充populateBean,属性填充好了之后,就将对象从缓存中取出来放在一级缓存,singletonObjects中
spring容器创建bean的大致流程是
1、A创建过程中需要B,于是A将自己放在三级缓存singletonFactory中,就去实例化B了
2、B 实例化的过程中发现自己需要A,于是从一级缓存singletonObjects中去查看,没有再去查看earlySingletonObjects,还是没有,再查三级缓存,发现A在三级缓存中,于是把三级缓存中的A就放到二级缓存中,并删除三级缓存里存储的A
3、得到二级缓存里的A之后,B顺利初始化完成,将自己放到一级缓存里面(此时的A还是在二级缓存中,依然是创建中的状态)然后回来接着创建A,此时A可以在一级缓存中直接拿到B,然后完成创建,并将A自己放到一级缓存里面