一、循环依赖
1、什么是循环依赖?
多个Bean之间相互依赖,形成一个闭环。例如:A依赖B,B依赖A。
2、spring两种注入方式对循环依赖的影响
spring的两种注入方式分别是构造器注入和setter注入。
我们AB循环依赖问题只要A的注入方式是setter且singleton,就不会有循环依赖的问题。
bean的注入方式,如果是原型注入那么就会出现循环依赖异常的问题。
我们可以结合spring官网文档:docs.spring.io/spring-fram…
3、spring的三级缓存
在介绍三级缓存之前,我们先了解一下初始化与实例化。
实例化:单独的创建一个对象,也就是我们说的new一个对象,或者是spring的工厂生产一个对象,但是对象里面的属性还没有填充值的时候。
初始化:就是对象里的属性赋值的过程就是初始化。
这个三级缓存在DefaultSingletonBeanRegistry类里面了。
1)、一级缓存:存放已经经历完生命周期的bean对象。也就是这个对象已经实例化,且它的属性也进行了初始化。 相当于一个成品,可以直接用。
/** Cache of singleton objects: bean name --> bean instance */ private final Map<String, Object> singletonObjects =
new ConcurrentHashMap<String, Object>(256);
复制代码
2)、二级缓存:存放早起暴漏出来的bean对象。bean的生命周期没有结束(属性还没填充完)。就是创建完对象了,但是对象的属性还没有填充值。
/** Cache of early singleton objects: bean name --> bean instance */ private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
复制代码
3)、三级缓存:存放可以生成bean的工厂。
/** Cache of singleton factories: bean name --> ObjectFactory */ private final Map<String, ObjectFactory<?>> singletonFactories =
new HashMap<String, ObjectFactory<?>>(16);
复制代码
总结:只有单例的bean会通过三级缓存提前暴露来解决循环依赖的问题,
而非单例的bean,每次从容器中获取的都是一个新的对象,都会重新创建,所以非单例的bean是没有缓存的,不会将其放到三级缓存中。
4、三级缓存的四大方法
getSingleton:从一级缓存中获取单例的bean
doCreateObject:在三级缓存中创建一个单例bean
populateBean:给单例的bean的属性填充值
addSingleton:把单例的bean加到一级缓存中
5、A/B两个对象在三级缓存中迁移的说明(此过程可以中面试中解释三级缓存解决循环依赖的过程)
1)、在A创建过程中需要B,于是A将自己放到三级缓存里面,去实例化B
2)、B实例化的时候发现需要A,于是B先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了A,然后把三级缓存中的A迁移到二级缓存中,并删除掉三级缓存中的A
3)、此时B顺利初始化完毕,将自己放到一级缓存里(此时B里面的A依然是创建中状态)
然后回来接着创建A,此时B创建结束了,直接从一级缓存中拿到B,然后A创建完成,此时从二级缓存迁移到一级缓存,并删除二级缓存中的A。