Подтвердить что ты не робот

Guice injector.getInstance() - хорошая практика?

Скажем, у меня есть два приложения, которые используют одну и ту же библиотеку. Эта библиотека содержит общие классы, такие как DAO, Utils и т.д. Все в общей библиотеке связано с Guice. Мои два приложения зависят от этой библиотеки, но не имеют прямой зависимости от Guice.

 ______    ______    ______
|      |  |      |  |      |
| APP1 |->| LIB  |<-| APP2 |
'------'  '------'  '------'

В настоящее время я использую что-то вроде этого:

static <T> Utils.getInstanceOf (Class<T> type);

который является просто оболочкой для:

injector.getInstance (Class<T> type);

Но в письме говорится:

Когда это возможно, избегайте использования этого метода в пользу наличия Guice заблаговременно вводите ваши зависимости.

Итак, что лучший способ обеспечить инъекцию зависимостей для двух приложений без необходимости вручную связывать их в модуле Guice?

4b9b3361

Ответ 1

Итак, какой лучший способ обеспечить инъекцию зависимостей для двух приложений без необходимости вручную связывать их в модуле Guice?

Нет такого пути. Вы либо полностью охватываете Guice, либо не используете его и явно передаете свои зависимости. Итак, структурируйте свой код таким образом, чтобы вы никогда напрямую не создавали зависимости классов, передавая их через конструктор, также можно назвать "инъекцией зависимостей", но я уверен, что это не то, что вы имели в виду. Если вы не хотите использовать Guice в своих приложениях, вы не сможете получить ничего лучше, чем getInstance(), что является уродливым, особенно потому, что вы используете статическую оболочку.

В идеале ваша библиотека должна предоставить модуль, который вы можете установить через Guice.createInjector() в своих приложениях, или, наоборот, библиотека должна предоставить экземпляр Injector, который вы можете использовать в своих приложениях, используя createChildInjector() и предоставление модулей, специфичных для приложения. Небольшая модификация этого подхода заключается в передаче в библиотеку модулей, специфичных для приложения, поэтому они будут использоваться для создания Injector. Недавно я написал API, основанный на Guice, над настраиваемым сервлет-подобным интерфейсом, который не поддерживал какой-либо DI вообще, используя последний подход, и он отлично работает.

Совсем не сложно использовать Guice в среде сервлетов или Джерси. Последнее, например, имеет встроенную интеграцию с Guice (по крайней мере, в версиях 1.x). Guice расширение сервлета также очень хорошо и удобно. Просто попробуйте и убедитесь сами.

Ответ 2

"Обычным" шаблоном использования инжектора является его настройка в некоторой точке входа верхнего уровня вашего проекта (в сценарии сервлетов, используя Guice-Servlet, это будет GuiceServletContextListener). Вы можете настроить индивидуальный инжектор в точке входа на некоторую зависимость и сделать его ответственным за подключение этой зависимости для модуляции. Если вы хотите как индивидуальные привязки, так и привязки из родительского проекта в ваших зависимостях, то вы можете создать дочерний инжектор, который делегирует его родительскому объекту, если привязка не найдена. Guice поддерживает это.

Однако мне кажется странным, что вы хотите настроить инжектор внутри зависимостей и использовать его в своих основных приложениях. Это означало бы, что зависимость знает обо всех привязках, необходимых для основного приложения (ов). Я не совсем уверен, чего вы пытаетесь достичь с помощью этого подхода. Разве что ваши два приложения имеют одну и ту же/очень похожую настройку привязки, и вы не хотите ее повторять? В этом случае вы должны определить модуль со всеми конфигурациями привязок один раз (возможно, в зависимости) и использовать его при настройке инжектора в точках входа в каждое из ваших приложений. Это касается вашего сценария.

На ваш вопрос в целом. Я считаю, что его хорошая практика избегать явного прохождения инжектора. Всякий раз, когда вы это делаете, вы работаете против идеи инъекции зависимостей как прозрачного проекта, и вы привязываетесь к конкретной структуре инъекций. В большинстве случаев вы можете избежать явных ссылок на инжектор, используя Провайдеры и Заводы.

Ответ 3

static <T> Utils.getInstanceOf (Class<T> type);

В результате вы обнаружили Сервис-локатор.

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

Ответ 4

Если у вас есть метод, который должен создать новый экземпляр класса C во время выполнения, привяжите провайдера к вашему классу. C будет связан обычным способом, например.

public CModule extends AbstractModule {
    @Overide
    public void configure() {
        bind(C.class).to(CImpl.class);
    }
}

Класс, создающий экземпляры C, будет выглядеть так:

class UserOfC {
    private Provider<C> cProvider;
    ...

    @Inject
    UserOfC(Provider<C> cProvider, ...) {
        this.cProvider = cProvider;
        ...
    }

    public void doSomethingWithAC (...) {
        C myC = cProvider.get();  // not a singleton; new instance created!
        ...
    }
}

Guice поддерживает бесплатную загрузку провайдера. Если C связан, вы можете ввести провайдера так же легко, как вы можете ввести экземпляр C.

Дополнительные предложения:

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

Когда я сталкиваюсь с необходимостью частичной инъекции, я обычно пишу свой собственный factory. Мне гораздо легче понять и отладить, когда я пишу код.

Ответ 5

Да, это нормально, чтобы передать инжектор таким образом.

Даже мы сделали что-то подобное с нашим калибровочным приложением, поэтому для страниц, не относящихся к калитке, мы просто использовали injector.get.inject(this) и передали в конструкторе.

и он отлично работает.

Надеюсь, что это поможет.