Spring ioc(4)---如何解决循环依赖
前面说到对象的创建,那么在创建的过程中Spring是怎么又是如何解决循环依赖的呢。前面提到有个三级缓存。就是利用这个来解决循环依赖。打个比方说实例化A的时候,先将A创建(早期对象)放入一个池子中。这个时候虽然属性没有赋值,但是容器已经能认识这个是A对象,只是属性全是null而已。在populateBean方法中对属性赋值的时候,发现A依赖了B,那么就先去创建B了,又走一遍bean的创建过程(创建B)。同样也会把B的早期对象放入缓存中。当B又走到populateBean方法的时候,发现依赖了A,好吧,我们又去创建A呗,但是这个时候去创建A,发现我们在缓存能找到A(早期对象)了。就可以把B的A属性赋值了,这个时候B就初始化完成了。现在回到A调用的populateBean方法中。返回的就是B对象了,对A的B属性进行赋值就可以了。流程如下:
这就是Spring IOC如何解决循环依赖的原理,但是IOC无法解决两种循环依赖,一种是非单例对象的,因为非单例对象不会放入缓存的。每次都是需要创建。二是通过构造器注入,也无法解决。从上面的流程可以看出,调用构造器创建实例是在createBeanInstance方法,而解决循环依赖是在populateBean这个方法中,执行顺序也决定了无法解决该种循环依赖。对于这种,如果喜欢使用lombok的@RequiredArgsConstructor注解的小伙伴就需要注意了,这个注解会生成一个带所有属性的构造方法。通过idea直接点开对应的class文件就可以看不看这个构造方法了。
问题:解决循环依赖一定要三级缓存嘛?
关键代码位置:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingletonFactory
首先我们的一级缓存是单例缓存池(singletonObjects),二级缓存是早期对象(earlySingletonObjects),三级缓存是一个包裹对象ObjectFactory(registeredSingletons),通过getObject获取到早期对象。
从上面的流程来看,实际上二级缓存已经可以解决循环依赖了,那么为什么Spring还要包裹出来一个三级缓存呢?
从Spring Ioc(3)---bean的实例化中的源码分析我们可以看到调用三级缓存中的getObject方法实际上是调用的org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#getEarlyBeanReference这个方法。
那么我就看看这个方法里面干了些什么事情:
执行SmartInstantiationAwareBeanPostProcessor这个类型处理器的getEarlyBeanReference方法。
断点调试,发现Spring原生中实现了这个接口的类org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter,实际上什么事情都没有干,直接返回了,
但是如果是AOP要切的对象,会在这里生成代理对象返回,AOP流程:Spring aop(1)--- 寻找切面和代理对象执行流程源码分析
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getEarlyBeanReference。
所以说第三级缓存其实是为了解决代理对象之间的循环依赖。