Управление сложными жизненными циклами в Guice

Я столкнулся с ситуацией, когда у меня есть граф объектов данных, и я хотел бы создать один сервис для каждого узла на этом графе. Проблема в том, что этот сервис (и его зависимости) зависят от узла, для которого они работают. Что-то вроде этого:

class Visitor {

  void enter(Node node){
    Service service = guice.create(node)

    service.doComplexDomainLogic(/*some runtime information about the graph and the path to get here, other things*/)
  }
}

Обратите внимание, что мое намерение состоит в том, чтобы создать новый экземпляр Service и новый экземпляр любых зависимостей для Service для каждого узла на графике.

Так что теперь у меня есть пара вариантов:

  • guice поддерживается вспомогательной инъекционной фабрикой. Это то, что мы делаем в настоящее время, и требует, чтобы зависимость от узла определялась во всем, от чего зависит сервис, если они тоже зависят от node, Другими словами, если я использую фабрику вспомогательных инъекций здесь, я должен использовать ее для каждого класса, который service зависит от того, что неприятно.
  • Я могу использовать то, что мы называем вложенными загрузчиками, то есть новый модуль с новым инжектором, эффективно новую среду, и в настройках для этой среды я могу написать bind(Node.class).toInstance(node), Этот код будет выполнен при первом посещении, и его результат будет кэширован.
  • Я могу использовать пользовательские рамки Guice (я думаю).

Мы сделали второе в паре мест просто потому, что я и моя команда не знали о пользовательских сферах. Теперь у нас есть еще одно использование настраиваемой области, и я должен признаться, что ее реализация была намного сложнее, чем хотелось бы. Следование этому руководству помогает, но ясно, что мне придется углубиться в безопасную землю, и мой последний визит был не таким приятным.

Какую услугу хитрости я должен использовать, чтобы получить это поведение?

1 ответ

Решение

Вы можете ввести Injector и создайте детский инжектор для частей, которые вы хотите. Дочерний инжектор позволит вам изменить граф объектов и получить доступ ко всем зависимостям родительского инжектора, но вы можете получить доступ к своему узлу настолько глубоко, насколько захотите.

class Visitor {
  @Inject Injector injector;

  void enter(final Node node) {
    Service service = injector.createChildInjector(new AbstractModule() {
      @Override public void configure() {
        bind(Node.class).toInstance(node);
        // Anything that does require a Node should be bound here, because
        // you can't define it in the parent due to the unsatisfied binding.
        bind(SomeInterface.class).to(SomeClassThatRequiresNode.class);
      }
    }).getInstance(Service.class);

    service.doComplexDomainLogic(/* ... */)
  }
}

Хотя с областями можно сделать нечто подобное, имейте в виду, что области предназначены только для определения того, когда создавать новый объект, а не когда возвращать тот же объект. Это означает, что вы можете создать @NodeScoped область и убедитесь, что одни и те же объекты будут возвращены при обработке данного узла, но вам все равно нужно будет связать некоторый вид @NodeScoped NodeHolder удерживать ваши узлы во время погружения. Вместо того, чтобы хранить и заполнять этот отдельный держатель, дочерний инжектор позволит вам напрямую запросить узел, что может сделать ваш код легче для понимания и тестирования.

Смотрите также:

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