Spring相关05——Spring Bean相关03-循环依赖2

79 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

为什么要三级缓存?

一级缓存不行,会将成品和半成品的对象放到一起,而半成品对象无法暴露给外部使用。

二级缓存行吗?如果整个应用程序中不涉及aop的存在那么二级缓存足以解决循环依赖的问题,但如果aop的动态代理对象中存在循环依赖就必须使用三级缓存因为代理对象的存在若A最终会创建代理对象,但提前暴露原始对象的引用,B填充的属性值会是A原始对象的引用等A代理对象的成品放入缓存中时,B属性的引用依然是A原始对象的引用,这不符合期望

三级缓存,三级缓存的value类型是ObjectFactory,是一个函数式接口,可以保证在整个容器的运行过程中同名的bean对象只有一个。

普通对象和代理对象是不能同时出现在容器中的,因此当一个对象需要被代理的时候,就要使用代理对象覆盖掉之前的普通对象,在实际的调用过程中,没有办法确定什么时候对象会被使用,所以就要求某个对象被调用的时候,优先判断此对象是否需要被代理,三级缓存中存放的ObjectFactory,可以根据对象是否需要代理返回代理对象的引用或原始对象的引用

缓存的放置时间和删除时间

三级缓存:CreateBeanInstance之后:addSingletonFactory

二级缓存:第一次从三级缓存确定对象是代理对象还是原始对象的时候,同时删除三级缓存:getSingleton

一级缓存:生成完整对象之后放到一级缓存,删除二级缓存:addSingleton

无法解决的循环依赖问题

为什么Spring不能解决构造器的循环依赖?

当存在循环依赖时,主bean对象不能通过构造函数的方式注入所依赖的bean对象,而所依赖的bean对象则不受限制,即可以通过三种注入方式的任意一种注入主bean对象。(构造函数、属性注入或者setter方法)

直接原因:是主bean对象通过构造函数注入所依赖bean对象时,无法创建依赖的bean对象

具体原因:创建主bean对象,调用顺序是:(1)如果主bean类存在构造函数,则执行构造函数(2)执行createBeanInstance方法,会调用addSingletonFactory方法将主bean对象的Bean工厂到singletonFactories中(3)对主bean进行属性赋值。

当存在构造函数时构造函数会在createBeanInstance方法前被调用,则会在将主bean对象的Bean工厂放入到singletonFactories之前初始化依赖bean对象,创建依赖bean时无法在三级缓存中找到主bean的信息(三级缓存singletonFactories找到主bean的Bean工厂),导致无法解决的循环依赖问题。

为什么不能解决多例Bean的循环依赖?

多例对象不会放入缓存池,所以无法从缓存池中获得对象,每次创建主bean时会创建依赖bean,创建依赖bean时又会新创建主bean,如此循环造成OOM