简单了解三级缓存解决循环依赖
什么是循环依赖问题?
Spring框架有个特点就是大量使用缓存,当Spring需要某个bean对象的时候,它不会直接创建这个bean,而是会先从缓存里面找,如果缓存中没有才会创建这个bean对象,比如Person对象有个Car属性,当Person对象属性赋值的时候就会去容器(缓存)里面拿,那么如果Car对象又有个Person属性,就会不断地重复这个过程,Person获取Car,Car又获取Person,最终方法无限递归造成栈溢出。
有什么办法进行属性赋值?
在Spring可以通过构造器或者set()方法进行属性赋值,又分为byName(如@Resource)或者byType(如@Autowired)。
Spring能够解决的只能解决单例bean和set()方法注入的循环依赖。
单例bean和多例bean
Spring是用了三级缓存存放提前暴露的半成品bean
而对于多例bean,没有使用缓存所以当Spring遇到多例bean的循环依赖将会直接抛出异常
set()方法和构造器
set()方法是属性赋值使用的办法,配合反射实现
构造器在对象实例化的时候被调用,将会调用getBean属性赋值,但是这里赋值的时候不会加载三级缓存,就会报错
三级缓存解决循环依赖
有哪些缓存?
1 | // 一级缓存,beanName -> 实例化并且初始化的成品 |
缓存加入时机
一级缓存
在singletonObject = singletonFactory.getObject();创建完完整的单例bean实例之后会把这个单例bean加入到一级缓存。
二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);把未完全初始化的bean从三级缓存提升到二级缓存。
三级缓存
在初始化之前,调用addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));把bean提前暴露到第三级缓存,防止循环依赖。
总结
其实本质上只有二级缓存,二级缓存提前暴露未完全初始化的单例bean,一级缓存是完整的单例bean,我们用二级缓存给属性赋值,而一级缓存来获取bean,如果有代理bean,那么就会造成beanA和b.属性beanA不同,那第三级缓存实际上是为了代理bean而存在的,我们需要通过第三层缓存SingletonFactory来生成代理对象,注意这里缓存是不能被替换的,只能够新增,所以采用多一级缓存才能对代理bean有效。