Как впрыскивать инжектор? - PullRequest
       31

Как впрыскивать инжектор?

29 голосов
/ 01 февраля 2010

Ситуация: в некоторых FooClass мне нужно создать ленивую зависимость, поэтому я передаю Injector в класс в качестве параметра конструктора.

private final Injector m_injector;

public FooClass(@Named("FooInjector") Injector injector) {
m_injector = injector;
}

Но guice не позволяет связывать базовые классы (инжекторы, модули и т. Д.). Какое решение?

Ответы [ 4 ]

28 голосов
/ 01 февраля 2010

Вы не должны использовать Injector напрямую. Скорее передайте Provider<FooClass> вместо этого. Кроме того, вы должны вводить провайдер в местах, где вы используете FooClass.

private final Provider<FooClass> provider;

@Inject
public ClassWhereFooIsUsed(Provider<FooClass> provider) {
    this.provider = provider;
}

.... somewhere else
FooClass f = provider.get(); // This is lazy
12 голосов
/ 06 июня 2011

Поскольку другие уже ответили, вы можете просто использовать @Inject Injector, потому что Guice определяет само связывание.

Обычно вам требуется только один Injector в вашем приложении, а статическая переменная является еще более простым способом хранения и доступа к синглтону, чем его внедрение. В нашем веб-приложении мы используем stripes-guicer и получаем Injector от статического метода GuiceInjectorFactory.getInjector(), когда он нам нужен (например, в нашем перехватчике Hibernate).

Я немного сбит с толку советом, что "вы не должны использовать Инжектор напрямую". Как еще я могу получить экземпляр за исключением вызова injector.getInstance() или injector.injectMembers()? Выхода нет. Да, вы можете определить методы Провайдера, но они никогда не будут вызываться, если где-то что-то использует Инжектор. Да, есть модули, которые используют для вас Injector, например ServletModule ; Вы должны создать Injector самостоятельно, но после этого можете оставить его на ServletModule.

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

8 голосов
/ 01 февраля 2010

Как сказал @gpampara, Provider<T> следует использовать для отложенной / необязательной инициализации. Кроме того, как я сказал в своем ответе на другой вопрос, вам следует избегать ссылок на Injector в вашем коде почти во всех случаях.

Тем не менее, в классе, который создается Guice, Injector, создающий объект, может быть введен, просто объявив зависимость от Injector. Injector автоматически доступен для инъекций, и вы не объявляете о его привязке.

Если вы вводите Injector, вам следует подумать, ПОЧЕМУ вы хотите это сделать. Почему бы вам просто не объявить зависимости от реальных интерфейсов / классов, от которых зависит класс? Так же просто добавить новую зависимость в конструктор, как и получить экземпляр некоторой зависимости через Injector в другом месте вашего кода, и это делает код гораздо более понятным.

2 голосов
/ 15 марта 2018

Аргументы, что вы , вероятно, не должны внедрять экземпляр Injector, вполне допустимы, но, как и в любом правиле, существуют исключения.

У меня есть фабричный класс, который принимает ссылки на классы, для которых он должен предоставить экземпляр. Случаи не обязательно известны (на самом деле, они есть, но их много, а может быть и больше), поэтому я не могу сделать провайдеров для всех них.

public class ThingFactory {
    private Injector injector;

    @Inject
    ThingFactory(Injector injector) {
        this.injector = injector;
    }

    public <T> T getInstance(Class<T> aClass) {
        return injector.getInstance(aClass);
    }
}

Настоящий класс в моем приложении расширяет и переопределяет другой класс, поэтому этот класс в сущности является проходом к Guice.

...