Как справиться с циклической зависимостью весной - PullRequest
3 голосов
/ 16 августа 2011

Например, у меня есть два 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;
   }

}

Теперь, если я попытаюсь настроить их весной следующим образом:

<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.Bean2 внедрил bean1, но сам bean1 инициализирован не полностью, поэтому вызов bean1.doStuff (), который вызовет service1.doActualStuff (), вернется в NPE.Почему bean1 не полностью инициализирован?

Ответы [ 2 ]

5 голосов
/ 16 августа 2011

Spring кэширует одноэлементные компоненты в не полностью инициализированном состоянии для внедрения в места, которые в противном случае были бы неразрешимой круговой ссылкой. В вашем случае порядок инициализации будет примерно таким:

  1. Создание экземпляра bean1 (имеется в виду вызов только конструктора, а не методов init)
  2. Добавление bean1 в одноэлементный кеш для обработки циклических зависимостей
  3. Начать вводить зависимости bean1
  4. Создание экземпляра bean2 для удовлетворения зависимости bean1
  5. Добавление bean2 в кэш Singelton для обработки циклических зависимостей
  6. Начать внедрение зависимостей bean2 - одна из них - это кэшированный экземпляр bean1, который еще не полностью инициализирован
  7. Завершить внедрение зависимостей bean2
  8. Вызовите метод инициализации bean2 - ух! bean1 еще не запущен!
  9. Завершено создание bean2
  10. (Если вы действительно сделали это так далеко ...) Закончите вводить зависимости bean1
  11. Нет метода init на bean1, но здесь он будет называться
  12. Завершено создание bean1

Попробуйте переосмыслить свой дизайн, чтобы распутать зависимости между bean1 и bean2.

0 голосов
/ 16 августа 2011

Как насчет того, если вы вводите первый боб программно:

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);
   }
}

Удалите первый укол из пружины 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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...