有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何在spring中处理循环依赖关系

例如,我有两个bean:

class Bean1 {
  private SomeService service1;
  private SomeService servive2;
  private Bean2 bean2;

  public void doStuff() {
     service1.doActualStuff();
  }

  public void setBean2(Bean2 bean2) {
     this.bean2 = bean2;
  }

  public Bean2 getBean2() { return this.bean2 }
}

class Bean2 {
   private Bean1 bean1;
   private SomeService3 service3;

   public void init() {
       bean1.doStuff();
   }

   public void setBean1(Bean1 bean1) {
      this.bean1 = bean1;
   }

}

现在,如果我尝试在spring中以以下方式配置它们:

<bean id="service1" class="SomeService">
    ...
</bean>
<bean id="bean1" class="Bean1">
   <property name="bean2" ref="bean2"/>
   <property name="service1" ref="service1"/>
   ...
</bean>
<bean id="bean2" class="Bean2" init-method="init">
   <property name="bean1" ref="bean1"/>
   ...
</bean>

执行bean2的Init方法。Bean2已注入bean1,但bean1本身未完全初始化,因此调用bean1。将调用service1的doStuff()。doActualStuff()将返回NPE。为什么bean1没有完全初始化


共 (2) 个答案

  1. # 1 楼答案

    Spring将处于未完全初始化状态的单例bean缓存起来,以便注入到不可解析的循环引用中。在您的情况下,初始化顺序如下:

    1. 实例化bean1(意味着只调用构造函数,而不是init方法)
    2. 将bean1添加到单例缓存以处理循环依赖项
    3. 开始注入bean1的依赖项
    4. 实例化bean2以满足bean1的依赖关系
    5. 将bean2添加到singelton缓存以处理循环依赖项
    6. 开始注入bean2的依赖项其中一个是缓存的bean1实例,它仍然没有完全初始化
    7. 完成注入bean2的依赖项
    8. 调用bean2的init方法uhoh!bean1还没有初始化
    9. 完成创建bean2
    10. (如果你真的做到了这一步…)完成注入bean1的依赖项
    11. bean1上没有init方法,但这是调用它的地方
    12. 完成创建bean1
    考虑重新设计你的设计,解开BeAN1和BeN2之间的依赖关系。

  2. # 2 楼答案

    如果您以编程方式注入第一个bean如何:

    class Bean2 {
       private Bean1 bean1;
       private SomeService3 service3;
    
       public void init() {
           bean1.doStuff();
       }
    
       public void setBean1(Bean1 bean1) {
          this.bean1 = bean1;
    
          //HERE
          this.bean1.setBean2(this);
       }
    }
    

    从spring xml中删除第一次注入:

    <bean id="service1" class="SomeService">
        ...
    </bean>
    <bean id="bean1" class="Bean1">
       <!  NOT NEEDED ANYMORE <property name="bean2" ref="bean2"/>  >
       <property name="service1" ref="service1"/>
       ...
    </bean>
    <bean id="bean2" class="Bean2" init-method="init">
       <property name="bean1" ref="bean1"/>
       ...
    </bean>