Гик-инъекция: разница между getBinding / getExistingBinding / getProvider и getInstance

У меня есть PropertiesModule который расширяет AbstractModule и содержит константы приложения, которые я использую во всем проекте:

 class PropertiesModule: AbstractModule(), Serializable { companion object { const val APP_NAME = "MyAppName" ... } override fun configure() { ... } } 

Затем я использую PropertiesModule для создания инжектора:

 ... val injector = Guice.createInjector( PropertiesModule(), ... ) 

И позже, когда я использую инжектор, чтобы получить значение свойства, у меня есть несколько вариантов. Я мог бы сделать:

 val appName = injector.getInstance( Key.get(String::class.java, Names.named(PropertiesModule.APP_NAME)) ) 

или

 val appName = injector.getExistingBinding( Key.get(String::class.java, Names.named(PropertiesModule.APP_NAME)) ).provider.get() 

или

 val appName = injector.getProvider( Key.get(String::class.java, Names.named(PropertiesModule.APP_NAME)) ).get() 

Я читал, что в общем случае getInstance следует избегать. Но я не уверен, в чем разница между ними.

    Если вы только что создали свой инжектор, используйте getInstance . В противном случае попробуйте получить ваш объект от более узкой инъекции.


    getBinding и getExistingBinding эффективно и для рефлексивных целей :

    [Связывание] – это отображение из ключа (тип и необязательная аннотация) в стратегию получения экземпляров типа. Этот интерфейс является частью API интроспекции и предназначен в основном для использования инструментами .

    Хотя это, вероятно, будет работать в некоторой степени, я бы рекомендовал против getExistingBinding , хотя бы потому, что он имеет противоречивое поведение не создавать привязки Just-In-Time, если они еще не существуют, как описано в документах getExistingBinding :

    В отличие от getBinding(Key) , это не пытается создать привязки точно в срок для ключей, которые не связаны. Этот метод является частью SPI Guice и предназначен для использования инструментами и расширениями.

    getProvider(Class<T>) будет закупать Provider<T> из графика, который похож на одноиндексный инжектор, который может создавать или извлекать экземпляры одного ключа из Инжектора. Подумайте об этом как о создании лямбды, которая вызывает getInstance для конкретного ключа, и не более того.

    getInstance – самый важный метод для Injector, и я ожидаю, что все приложения Guice вызовут его хотя бы один раз. Если вы только что создали свой Инжектор, вы, вероятно, захотите либо получить экземпляр из него , либо ввести поля @Inject объекта . Первый имеет место с getInstance , а второй – с injectMembers . На мой взгляд, это лучший способ получить первый объект из вашего графика.

    Тем не менее, и именно здесь вы injectMembers совет: вы, вероятно, не должны использовать Инжектор после первого вызова getInstance или injectMembers . Это связано с тем, что цель в Guice состоит в том, чтобы сделать независимые компоненты, которые выражают свои зависимости узко, чтобы вы могли легко заменить эти зависимости. Это основное преимущество инъекции зависимостей. Несмотря на то, что у вас есть варианты ставить Инжектор где-то статичным или вводить сам инжектор в ваши зависимости, это мешает вам точно знать, что такое зависимости вашего класса: при инъекции Injector вы можете вводить что угодно в мире.

    Чтобы продемонстрировать (пожалуйста, простите мою неопытность Kotlin):

     class BadIdea @Inject constructor(injector: Injector) { fun doSomething() { // Bad idea: you don't express this dependency anywhere, and this code // is nearly unusable without a real Guice Injector val appName = injector.getInstance( Key.get(String::class.java, Names.named(PropertiesModule.APP_NAME)) ) } } class WorseIdea { fun doSomething() { // Worse idea: same as the above, but now you rely on a static! val appName = StaticInjectorHolder.getInjector().getInstance( Key.get(String::class.java, Names.named(PropertiesModule.APP_NAME)) ) } } class GoodIdea @Inject constructor(@Named(PropertiesModule.APP_NAME) appName: String) { fun doSomething() { // Good idea: you express your dep, and anyone can call the constructor // manually, including you in your unit tests. } } 
    Intereting Posts
    Ни один из следующих кандидатов не отвечает из-за несоответствия типа приемника коллекции kotlin, преобразующие карту в новую карту со значениями, вычисленными из оригинала Конструктор, принимающий конструктивный конструктор в производном классе Котлин Пользовательский Джерси ExceptionMapper весной Boot с kotlin Нельзя использовать проверку весов с MongoDB Могу ли я импортировать библиотеку в Kotlin в мой проект андроида (использует java) Kotlin inheritnce – Не передано значение для контекста параметра Невозможно вернуть факториальный результат в функцию tailrec в Котлине Escape зарезервированные слова в импорте Исключение OutOfMemory при использовании Kotlin :: class.java.canonicalName AutoValue с GsonTypeAdapter в Котлине Как правильно сериализовать такой JSON с помощью GSON Android? Какова наиболее вероятная причина исключений, загадочно избегающих блока try-catch в этом случае? где поставить скрипт, который запускается во всех / некоторых действиях в android? Как вводить IoC в функции верхнего уровня Kotlin? Я даже использую контейнеры IoC?