什么是三级缓存
- singletonObjects: 一级缓存,用于保存实例化、注入、初始化完成的bean实例【完全体】
- earlySingletonObjects: 二级缓存,用于保存实例化完成的bean实例
- singletonFactories: 三级缓存,用于保存bean创建工厂,以便于后面扩展有机会创建代理对象。
什么是循环依赖
一个或者多个对象之间存在直接或者间接的依赖关系,形成一个环状依赖。
存在:自己依赖自己;两者互相依赖(如下图);多个对象间接依赖。
代码示例,以下会以此代码示例讲解:
@Service
public class DemoServiceImpl_01 {@Autowiredprivate DemoServiceImpl_02 demoServiceImpl_02;
}@Service
public class DemoServiceImpl_02 {@Autowiredprivate DemoServiceImpl_01 demoServiceImpl_01;
}
bean加载流程
spring能解决循环依赖的本质
spring能解决循环依赖的本质是:bean的实例化和初始化是分开执行的,利用三级缓存的设置可以将实例化后的对象缓存到二级缓存,在依赖注入的时候会先尝试从一级缓存获取对象,如果没有再尝试从二级缓存,三级缓存中去获取。
以下我们先举个循环依赖的例子:
// TestService1,TestService2都只有唯一一个构造器,实例化的时候就必须处理依赖注入的对象TestService2
// 但是依赖注入的对象TestService2的实例化也依赖TestService1的实例化,因此造成循环依赖@Service
public class TestService1 {public TestService1(TestService2 testService2) {}
}@Service
public class TestService2 {public TestService2(TestService1 testService1) {}
}运行结果:
Requested bean is currently in creation: Is there an unresolvable circular reference?
探究三级缓存的必要性
一级缓存是否必须存在
一级缓存,用于保存实例化、注入、初始化完成的bean实例【完全体】,毋庸置疑,一级缓存必须存在。
二级缓存是否必须存在
讨论这个问题,我们得知道三级缓存中的ObjectFactory具体是干什么的?
从源码可以看出,在bean实例化之后,初始化之前,spring会将实例化好的bean封装成一个ObjectFactory对象放入三级缓存,那么这么做是为什么呢?其实是为了做AOP增强。
AbstractAutoProxyCreator 继承 SmartInstantiationAwareBeanPostProcessor,SmartInstantiationAwareBeanPostProcessor正是ObjectFactory#getEarlyBeanReference里面要处理的后置处理器。
那么回到正题,知道了三级缓存的作用,为什么二级缓存必须得有呢?
当调用getBean()时,会先尝试从缓存中获取(如上图代码),这时候是一级缓存->二级缓存->三级缓存,这里面会有一个细节:从三级缓存中取完后会将对应ObjectFactory删掉,然后将获取的对象放入二级缓存;这时候如果没有二级缓存的话,每次走到此处都要从三级缓存中获取对象,如果对象需要代理,那么每次获取到的代理对象将会不是同一个对象,故二级缓存必须有。
三级缓存是否必须存在
其实我一直有一个疑问,我是否可以不要三级缓存,在添加三级缓存时,我立马处理bean的增强逻辑,并将增强后的bean存入二级缓存?
其实从bean生命周期设计的角度来看,最好是当我实例化,初始化完成后再去考虑增强的事,从源码设计来看,利用三级缓存存储ObjectFactory来实现AOP增强的滞后处理。