Spring的循环依赖
什么是循环依赖
首先,我们需要知道什么是依赖,当对象A持有对象B的引用的时候,我们可以称A对象依赖于B对象。所以很容易理解到循环依赖就是在这个依赖关系中出现了一个循环。比如A依赖B、B依赖A。或者A->B->C->A这种。
spring怎么解决
spring解决循环依赖的依据是java基于引用传递。所以当我们需要设定一个对象的属性的时候其实是可以延后设置的。spring中的对象初始化其实可以分为三步:
- createBeanInstance,实例化,实际上就是调用对应的构造方法构造对象,此时只是调用了构造方法,spring xml中指定的property并没有进行populate
- populateBean,填充属性,这步对spring xml中指定的property进行populate
- initializeBean,调用spring xml中指定的init方法,或者AfterPropertiesSet方法
会发生循环依赖的步骤集中在第一步和第二步。
spring能解决的循环依赖只能是 一二、二二组合的循环依赖问题,如果二者依赖都发生在第一步。那么spring也无法解决。
spring通过三层缓存的方式提前暴露已经实例化但没有进行属性设置的对象来解决循环依赖。,Spring首先从singletonObjects(一级缓存)中尝试获取,如果获取不到并且对象在创建中,则尝试从earlySingletonObjects(二级缓存)中获取,如果还是获取不到并且允许从singletonFactories通过getObject获取,则通过singletonFactory.getObject()(三级缓存)获取。如果获取到对象则放入二级缓存中。
具体举例:
A首先完成了初始化的第一步,并且将自己提前曝光到singletonFactories中,此时进行初始化的第二步,发现自己依赖对象B,此时就尝试去get(B),发现B还没有被create,所以走create流程,B在初始化第一步的时候发现自己依赖了对象A,于是尝试get(A),尝试一级缓存singletonObjects(肯定没有,因为A还没初始化完全),尝试二级缓存earlySingletonObjects(也没有),尝试三级缓存singletonFactories,由于A通过ObjectFactory将自己提前曝光了,所以B能够通过ObjectFactory.getObject拿到A对象(虽然A还没有初始化完全,但是总比没有好呀),B拿到A对象后顺利完成了初始化阶段1、2、3,完全初始化之后将自己放入到一级缓存singletonObjects中。此时返回A中,A此时能拿到B的对象顺利完成自己的初始化阶段2、3,最终A也完成了初始化。