2013-10-11 6 views
13

Предположим, у меня есть два приложения, которые используют одну и ту же библиотеку. Эта библиотека содержит общие классы, такие как DAO, Utils и т. Д. Все в общей библиотеке связано с Guice. Мои два приложения зависят от этой библиотеки, но не имеют прямой зависимости от Guice.Guice injector.getInstance() - хорошая практика?

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

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

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

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

injector.getInstance (Class<T> type); 

Но Guice документы говорят:

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

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

+1

Означает ли ваш дизайн использование '@ Inject'? – chrylis

+0

Совсем нет. Я использую его по общей библиотеке. Забыл упомянуть, что в клиентских приложениях есть сервлеты и классы REST Джерси в них - например, веб-приложения, запущенные в контейнере сервлетов (не JavaEE). – albogdano

ответ

9

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

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

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

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

+0

Итак, все в порядке, чтобы передать экземпляр «Инжектор»? Я пытался избежать этого. – albogdano

+2

@ AlexB No-no-no. Я не это имел в виду. Наверное, я не прояснил ситуацию и, вероятно, ошибся. Я обновил ответ. –

+0

Теперь это имеет больше смысла, спасибо Владимиру! – albogdano

0

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

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

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

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

2

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

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

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

+0

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

+0

Вы сами говорите «еще», подразумевая, что в будущем могут быть отдельные привязки. Это совершенно нормально и может быть легко достигнуто, учитывая, что ваши приложения создают собственный инжектор, используя общий модуль. Я вижу код конфигурации инжектора, такой как файл конфигурации: это нормально менять, оно должно быть расположено в приложении, которое оно настраивает, потому что именно там я бы его искал - и он должен быть в классе, который делает ничего, кроме конфигурации. –

2

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

То, что вы в конечном итоге с является Service Locator.

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

1

Если у вас есть метод, который должен создать новый экземпляр класса 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 инъекции Provider поддерживает не бесплатно даром. Если С границей, вы можете вводить поставщика так же легко, как вы можете придать экземпляр C.

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

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

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

Смежные вопросы