Почему afIoc не внедряет сервис в этом случае?

Я пытаюсь создать очень простое приложение, используя инфраструктуру IoC для Fantom afIoc, чтобы ознакомиться с ним. Я попробовал это...

using afIoc

class Main {
  Registry registry := IocService([AppModule#]).start.registry

  @Inject
  myPod::Version? version

  Void main() {
    echo("version is $version")
  }    
}

Класс версии

const class Version {
  override Str toStr() {
    "0.0.1"
  }
}

AppModule это

using afIoc

class AppModule {
  static Void bind(ServiceBinder binder) {
    binder.bind(myPod::Version#)
  }
}

Компилирует но печатает version is null, Я исправил проблему, переопределив мой основной класс:

using afIoc

class Main {

  Registry registry := IocService([AppModule#]).start.registry

  Void main() {
    version := (myPod::Version) registry.serviceById("myPod::Version")
    echo("version is $version")
  }
}

Но я хотел бы понять жизненный цикл реестра afIoc и почему сервис Version не внедряется в мою первую версию класса Main. Кто-нибудь может объяснить, пожалуйста?

1 ответ

Решение

Я видел, как люди задают похожие вопросы о других IoC-средах... Итак, давайте посмотрим, что происходит, когда вы запускаете программу:

using afIoc

class Main {  //................................................... 1
  Registry registry := IocService([AppModule#]).start.registry //.. 2

  @Inject
  myPod::Version? version //....................................... 3

  Void main() {
    echo("version is $version") //................................. 4
  }    
}
  1. Фантом создает Main учебный класс.

  2. Фантом создает registry поле и присваивает его результат IocService([AppModule#]).start.registry, Этот оператор просто создает и возвращает реестр IoC.

  3. Фантом создает version поля и по умолчанию это null,

  4. Фантом называет main() метод, который распечатывает version, который null,

Обратите внимание, что нигде выше мы не просили IoC вмешиваться с нашими Main учебный класс. Мы только что создали реестр IoC и установили его в поле.

Если мы хотим, чтобы IoC вводил значения в класс, мы должны попросить его:

  Void main() {
    registry.injectIntoFields(this)

    echo("version is $version")  // --> version is 0.0.1
  }

Или мы могли бы попросить IoC создать новый экземпляр Main для нас:

registry.autobuild(Main#)

Обратите внимание, что многие звонки autobuild() создаст много экземпляров Main,

Для IoC создать только один экземпляр Main (единичный), определите его как услугу в AppModule и использовать regsitry.serviceById() или же registry.dependencyByType() - так же, как вы обнаружили с Version,

Другие вопросы по тегам