源码分析spring如何解决循环依赖
-
Spring框架通过使用三级缓存和提前暴露的方式来解决循环依赖的问题。
首先,Spring通过三级缓存的方式来处理循环依赖。当Bean A依赖于Bean B,而Bean B又依赖于Bean A时,Spring会分别创建Bean A和Bean B的原始对象,并将它们放入三级缓存中。接着,Spring会先填充Bean A的属性,然后再处理Bean B的属性。在属性填充的过程中,如果发现循环依赖,则会从三级缓存中获取原始对象,并将其注入到相应的属性中。通过三级缓存的机制,Spring能够在循环依赖中解决Bean的创建和属性注入的顺序问题。
其次,Spring使用提前暴露的方式来解决循环依赖。当一个Bean正在创建的过程中,Spring会将其存放在二级缓存中,表示该Bean已经开始创建但还未完全创建完成。当另一个Bean需要依赖于正在创建的Bean时,Spring会先从二级缓存中获取该Bean的代理对象,并将其注入到相应的属性中。通过提前暴露的方式,Spring能够在循环依赖中解决Bean创建过程中的提前引用问题。
综上所述,Spring通过三级缓存和提前暴露的方式来解决循环依赖的问题。通过这两种机制,Spring能够保证Bean的创建和属性的注入在循环依赖中的正确顺序,并确保循环依赖的Bean能够正确地引用和注入。这也是Spring框架在处理循环依赖问题时的核心机制。
2年前 -
循环依赖是指两个或多个bean之间互相依赖,形成了一个循环的依赖关系。在Spring容器中,解决循环依赖是一个复杂的问题,需要涉及到Bean的创建、初始化和依赖注入等多个阶段。下面是Spring解决循环依赖的源码分析:
-
创建Bean的过程
在Spring容器启动时,首先会解析和加载配置文件,确定所有的Bean定义。然后,根据Bean定义创建Bean实例。Spring使用扩展了BeanFactory接口的DefaultListableBeanFactory类作为容器的默认实现。在创建Bean实例时,会根据依赖关系确定Bean的创建顺序,并将Bean实例注册到容器中。 -
提前暴露未完成的Bean
为了解决循环依赖问题,Spring会提前暴露正在创建的Bean实例,但是只暴露一个未完成的Bean引用,而不是完全初始化的Bean对象。这样,在依赖该Bean的其他Bean中,可以通过一个ObjectFactory对象来获取到该Bean的引用。 -
使用缓存来解决循环依赖
Spring使用三级缓存(三级Map)来解决循环依赖。在创建Bean实例的过程中,首先会检查一级缓存(singletonsCurrentlyInCreation),判断Bean是否已经在创建中。如果是,则说明存在循环依赖,会直接返回一个ObjectFactory对象。如果不是,则继续检查二级缓存(earlySingletonObjects),判断Bean是否已经创建完成但还未完全初始化。如果是,则直接返回Bean实例。如果不是,则继续检查三级缓存(singletonFactories),判断是否已经存在Bean的创建工厂。如果存在,则返回一个ObjectFactory对象,否则继续创建Bean实例。 -
通过代理来解决循环依赖
当一个Bean的依赖关系中存在循环依赖时,Spring会创建一个代理对象来解决循环依赖。代理对象在依赖注入时,会返回一个未完成的Bean引用。当被依赖的Bean被创建完成后,会触发代理对象的回调方法,来实现依赖注入。 -
提前暴露依赖
在解决循环依赖过程中,Spring还会提前暴露已经创建完成但还未完全初始化的Bean实例,以满足其他Bean对该Bean的依赖。这样,当其他Bean需要该Bean时,可以通过提前暴露的Bean引用来进行依赖注入,避免了循环依赖的问题。
综上所述,Spring通过使用缓存、提前暴露未完成的Bean、使用代理等方式,来解决循环依赖的问题。这些策略保证了Bean的创建和依赖注入的顺序,确保循环依赖时的正确处理。
2年前 -
-
循环依赖是指两个或多个Bean之间相互依赖,形成了一个环状依赖关系。在Spring中,循环依赖是一个常见的问题,但Spring框架提供了一些机制来解决循环依赖。下面是Spring框架解决循环依赖的源码分析。
-
循环依赖的检测
Spring在初始化Bean时,会将正在创建的Bean放入一个Map中,用于缓存已经创建但还未完全初始化的Bean对象。然后,在每个Bean的初始化过程中,会检查当前Bean是否正在创建中,如果正在创建中,说明存在循环依赖。 -
三级缓存的使用
在Spring中,存在三级缓存,用于处理循环依赖。三级缓存分别是:singletonFactories、earlySingletonObjects和singletonObjects。
singletonFactories:用于缓存正在创建中的Bean对象的工厂,即正在被创建但还未初始化完成的Bean。
earlySingletonObjects:用于缓存早期完全初始化的Bean对象,即已经完成初始化但还不是最终版本的Bean。
singletonObjects:用于缓存最终初始化完成的Bean对象。- 解决循环依赖的过程
当发现循环依赖时,Spring会先尝试使用缓存中的Bean对象来满足依赖关系,如果缓存中有已经初始化的Bean对象,那么会直接返回给依赖该对象的其他Bean。
如果缓存中没有对应的Bean对象,Spring会创建一个ObjectFactory,用于创建Bean的代理对象。然后将其放入singletonFactories缓存中,并将该ObjectFactory作为当前正在创建Bean的代理对象。
接下来,Spring会继续初始化该Bean,然后通过AutowireCapableBeanFactory接口的applyBeanPostProcessorsBeforeInitialization方法对Bean进行前置处理,主要是触发BeanPostProcessor的postProcessBeforeInitialization方法。
在Bean的初始化阶段,如果发现Bean的依赖关系中有循环依赖的情况,在初始化Bean的过程中,会先将该Bean添加到earlySingletonObjects缓存中,然后再出现循环依赖的属性注入时,会从earlySingletonObjects缓存中获取相应的Bean对象进行注入。
当Bean初始化完成后,在完成后的处理中,会将Bean从earlySingletonObjects缓存中移除,并将Bean添加到singletonObjects缓存中。
- 延迟依赖注入
Spring支持延迟依赖注入,即在Bean初始化完成后再进行属性注入。在解决循环依赖的过程中,如果某个Bean无法完成初始化,依赖该Bean的其他Bean也无法完成初始化,此时就会使用延迟依赖注入来解决这个问题。
总结:
Spring框架通过三级缓存的机制来处理循环依赖的问题。它使用缓存来管理已经初始化但还不是最终版本的Bean对象,并在循环依赖的属性注入阶段使用缓存中的Bean对象进行注入。同时,Spring还支持延迟依赖注入,以解决无法完成初始化的Bean导致其他Bean无法完成初始化的问题。通过以上机制,Spring能够有效地处理循环依赖,确保Bean的正确初始化和注入。2年前 -