- 背景介绍
大家都知道在ServiceA中依赖注入了ServiceB,ServiceB中又依赖注入了ServiceA,这就会出现循环依赖问题的,并且spring是通过三级缓存来解决循环依赖的问题的。 - 三级缓存介绍
private final Map<String, Object> singletonObjects 一级缓存
private final Map<String, Object> earlySingletonObjects 二级缓存
private final Map<String, ObjectFactory<?>> singletonFactories 三级缓存
①一级缓存存储的是:单例Bean对象,完整的单例Bean对象,也就是说这个缓存中的Bean对象的属性都已经赋值了;是一个完整的Bean对象(已经赋值)!
②二级缓存存储的是:早期的单例Bean对象,这个缓存中的单例Bean对象的属性没有赋值,只是一个早期的实例对象(没有赋值)!
③三级缓存存储的是:单例工厂对象,这个里面存储了大量的“工厂对象”,每一个单例Bean对象都会对应一个单例工厂对象;这个集合中存储的是,创建该单例对象时对应的那个单例工厂对象。 - 三级缓存是如何发挥作用的
还是以ServiceA中依赖注入了ServiceB,ServiceB中又依赖注入了ServiceA为例。
- ServiceA在实例化之前会从一级缓存中拿,如果没有,则实例化,并且包装成ObjectFactory放到三级缓存中
- ServiceA在依赖注入的时候发现了ServiceB,则会从一级缓存中拿,如果没有,则去实例化ServiceB,并且包装成ObjectFactory放到三级缓存中
- ServiceB在依赖注入的时候又发现了ServiceA,然后会去一级缓存中拿,拿不到再去二级缓存中拿,二级缓存中拿不到,再去三级缓存中拿。拿到ServiceA的ObjectFactory之后,获取到半成品的bean对象放到二级缓存,并且删除三级缓存中ServiceA的ObjectFactory对象,返回返回这个bean,从而完成ServiceB中ServiceA的依赖注入
- ServiceB依赖注入完成,进行初始化操作,完成之后把ServiceB放到一级缓存中,并且在二级缓存和三级缓存中清空ServiceB。至此ServiceB的创建工作完成。
- ServiceA直接从一级缓存中拿到ServiceB,从而完成ServiceA中ServiceB的依赖注入,然后进行初始化操作,最后把ServiceA放到一级缓存中,并且清空二级缓存和三级缓存中ServiceA。至此ServiceA的创建工作完成。
- 可以不要二级缓存吗
不行。假如还有一个ServiceC,ServiceA同时依赖了ServiceB和ServiceC,ServiceB依赖ServiceA,ServiceC依赖ServiceA。在ServiceB中依赖注入ServiceA的时候,会从三级缓存中拿到ObjectFactory对象,并且拿到对应的bean对象,然后删除三级缓存,并且放入二级缓存。假设这里没有二级缓存,那么当ServiceC在依赖注入ServiceA的时候,三级缓存中的ServiceA已经不存在了,也就没法注入ServiceA了,假设有二级缓存的话,这个地方可以直接从二级缓存中拿到ServiceA。所以这就是为什么需要二级缓存的原因。 - 可以不要三级缓存吗
当然也是不行。因为在把对象提前暴露到三级缓存中的时候,如果这个对象需要aop,放到二级缓存中的对象就应该是它的代理对象,否则是普通对象。spring会判断这个需要aop的对象,是否存在循环依赖。如果存在循环依赖,在通过三级缓存把ObjectFactory生成的bean放到二级缓存中的过程,会生成它的代理对象放到二级缓存,否则会直接把的它原始对象放到耳机缓存。这也就是为什么只把这个对象的ObjectFactory对象放到三级缓存中的原因。