spring循环依赖怎么回事

fiy 其他 40

回复

共3条回复 我来回复
  • 不及物动词的头像
    不及物动词
    这个人很懒,什么都没有留下~
    评论

    Spring中的循环依赖是指在不同的Bean之间存在相互依赖的情况,即A依赖于B,而B又依赖于A。这种循环依赖可能导致Bean的创建失败或进入无限循环的状态。

    Spring容器在处理循环依赖时使用了三级缓存,即单例对象的缓存,用于解决循环依赖的问题。具体处理流程如下:

    1. 遇到循环依赖的情况时,Spring会提前暴露正在创建的Bean对象,并将其置为early singleton状态。

    2. 首先,Spring会尝试使用构造函数注入来创建Bean。如果构造函数中有对其他Bean的依赖,则会在缓存中查找该Bean是否已经存在。若存在,则直接返回。若不存在,则继续递归创建依赖的Bean。

    3. 如果构造函数注入无法解决循环依赖的问题,Spring会使用setter方法注入。

    4. 当一个Bean的创建过程中需要获取依赖的其他Bean时,Spring会将正在创建的Bean标记为“正在创建中”,并将其放入缓存的第二级中。

    5. 如果发现正在创建的Bean已经在第二级缓存中,表明存在循环依赖的情况,Spring会尝试使用代理对象来满足依赖。同时,将正在创建的Bean放入缓存的第三级中。

    6. 当一个Bean创建完成后,Spring会将其从第二级和第三级缓存中移除。

    需要注意的是,循环依赖会增加系统的复杂度,可能导致不易察觉的bug。因此,在设计应用程序时应尽量避免循环依赖的发生,或者考虑重构代码来解决循环依赖问题。同时,可以使用一些依赖注入框架如Spring来处理循环依赖,减少对开发者的影响。另外,在构建复杂的依赖关系时,可以考虑使用延迟加载或者异步加载来优化系统的性能。

    1年前 0条评论
  • fiy的头像
    fiy
    Worktile&PingCode市场小伙伴
    评论

    Spring循环依赖是指在Spring容器中,两个或多个Bean之间存在相互依赖的情况。这种情况下,Bean A依赖于Bean B,同时Bean B又依赖于Bean A,形成了循环依赖关系。

    Spring循环依赖的产生可以分为构造器循环依赖和setter循环依赖两种情况。

    1. 构造器循环依赖:当Bean A通过构造器依赖Bean B,而Bean B又通过构造器依赖Bean A时,就会产生构造器循环依赖。在这种情况下,Spring无法解决循环依赖,会抛出BeanCurrentlyInCreationException异常。

    2. setter循环依赖:当Bean A通过setter方法依赖Bean B,而Bean B又通过setter方法依赖Bean A时,就会产生setter循环依赖。Spring可以通过三级缓存来解决setter循环依赖的问题。当检测到循环依赖时,Spring将其中一个Bean先实例化为一个半成品对象,然后将其注入到另一个Bean中,待另一个Bean完成实例化后再将其注入到之前的半成品对象中,从而完成循环依赖的解决。

    3. 循环依赖的解决策略:Spring通过三级缓存和BeanPostProcessor接口来解决循环依赖。三级缓存由singletonFactories、earlySingletonObjects和singletonObjects组成。当检测到循环依赖时,Spring将循环依赖的Bean标记为正在创建中,并放入singletonFactories中。然后,Spring会尝试创建其他Bean,直到循环依赖的Bean可以完成实例化,将其放入singletonObjects中。最后,Spring会通过调用BeanPostProcessor接口中的方法来处理循环依赖。

    4. 避免循环依赖:为了避免循环依赖的发生,可以通过以下几种方法:

      • 使用构造器注入代替setter注入,将依赖关系通过构造器参数传递。
      • 将循环依赖关系拆分为两个或多个接口,使用JDK动态代理或CGLIB动态代理来创建代理对象,从而避免循环依赖。
      • 将Bean定义为prototype作用域,而非singleton作用域。
    5. 注意事项:在解决循环依赖时需要注意以下几点:

      • 循环依赖可能导致死锁,因此需要仔细设计Bean之间的依赖关系。
      • 循环依赖会增加系统的复杂性和耦合性,尽量避免发生循环依赖。
      • 如果无法避免循环依赖,需要确保循环依赖的Bean的初始化逻辑正确,否则可能导致程序异常或错误的结果。
    1年前 0条评论
  • worktile的头像
    worktile
    Worktile官方账号
    评论

    Spring 循环依赖是指在 Spring 容器中存在两个或多个 Bean 之间相互依赖的情况。这种循环依赖会导致 Bean 的初始化过程不能顺利完成,从而引发异常。

    Spring 提供了解决循环依赖的机制,其中一种方式是使用 Setter 方法进行依赖注入。当检测到循环依赖时,Spring 会创建一个代理对象来延迟注入依赖。另一种方式是通过构造函数注入,Spring 在检测到循环依赖时会抛出一个异常,因为构造函数是在对象创建时就要求传入依赖的。

    下面将详细介绍 Spring 循环依赖的处理过程。

    1. 检测循环依赖

    当创建 Bean 的过程中,Spring 会检测是否存在循环依赖。检测的方式通常有两种:一种是使用三级缓存,另一种是使用构造器参数缓存。

    1.1 三级缓存检测

    Spring 在创建 Bean 的过程中会使用三级缓存,分别是 singletonFactories、earlySingletonObjects、singletonObjects。在创建 Bean 的过程中,首先会将 BeanDefinition 和代理对象的 FactoryObject 放入 singletonFactories 中,然后再将创建中的 Bean 放入 earlySingletonObjects,最后再放入 singletonObjects。在这个过程中,Spring 会检测当前要创建的 Bean 是否已经在 earlySingletonObjects 中,如果存在,则说明存在循环依赖,Spring 会尽早暴露创建中的 Bean。

    1.2 构造器参数缓存检测

    当 Bean 构造过程中存在循环依赖时,Spring 会在构造器参数缓存中查找是否存在正在构造中的 Bean。如果存在,则抛出异常提示循环依赖。这是因为构造器参数注入是在创建对象时要求传入全部依赖的,所以无法使用代理对象来解决循环依赖。

    2. 解决循环依赖

    Spring 提供的解决循环依赖的方式主要有两种:构造器注入和 Setter 方法注入。

    2.1 构造器注入

    构造器注入是指在创建对象时,通过构造函数将所有的依赖注入到对象中。这种方式下,如果存在循环依赖,Spring 会在创建对象时抛出 BeanCurrentlyInCreationException 异常,防止循环引用造成的死循环。此时,需要考虑修改对象的设计,尽量避免循环依赖的产生。

    2.2 Setter 方法注入

    Setter 方法注入是指在对象创建完成后,通过 Setter 方法将依赖注入到对象中。这种方式下,Spring 使用三级缓存和代理对象来解决循环依赖的问题。

    当检测到循环依赖时,Spring 会首先创建一个空对象放入缓存中,然后再注入其他的依赖。这样,依赖的 Bean 会去关联还未初始化完成的对象,从而形成循环依赖关系。当循环依赖结束后,再通过代理对象调用真正的初始化方法完成对象的创建。

    3. 循环依赖的注意事项

    虽然 Spring 提供了解决循环依赖的机制,但是在实际开发中,还是需要注意一些细节。

    3.1 构造器注入的限制

    构造器注入是无法解决循环依赖问题的,而且也会引起一些其他的问题。因此,在设计对象之间的依赖关系时,应尽量避免构造器注入的方式。

    3.2 Setter 方法注入的性能开销

    Setter 方法注入使用代理对象来解决循环依赖问题,但是这也会带来一定的性能开销。因此,在需要考虑性能的场景下,应慎重选择依赖注入的方式。

    3.3 循环依赖的限制

    在 Spring 容器中,循环依赖是存在一定的限制的。默认情况下,Spring 容器只能解决单例 Bean 之间的循环依赖,原型 Bean 和其他作用域的 Bean 是无法解决循环依赖的。

    为了解决这个问题,可以使用 ObjectFactory 或者 ObjectProvider 来间接获取原型 Bean,从而绕开循环依赖的检测。

    总之,循环依赖是一个常见的问题,在使用 Spring 开发应用时需要注意处理循环依赖的方式,避免出现死循环或者无法完成 Bean 初始化的情况。同时,也要避免使用构造器注入,减少开发过程中出现的循环依赖问题。

    1年前 0条评论
注册PingCode 在线客服
站长微信
站长微信
电话联系

400-800-1024

工作日9:30-21:00在线

分享本页
返回顶部