Kotlin guice注入:getBinding/getExistingBinding/getProvider和getInstance之间的区别

Kotlin guice注入:getBinding/getExistingBinding/getProvider和getInstance之间的区别,kotlin,guice,Kotlin,Guice,我有一个属性模块,它扩展了抽象模块,并包含我在整个项目中使用的应用程序常量: class PropertiesModule: AbstractModule(), Serializable { companion object { const val APP_NAME = "MyAppName" ... } override fun configure() { ... } } 然后我使用属性模块创建喷油器: ... val injector = Guice

我有一个
属性模块
,它扩展了
抽象模块
,并包含我在整个项目中使用的应用程序常量:

class PropertiesModule: AbstractModule(), Serializable {
  companion object {
    const val APP_NAME = "MyAppName"
    ...
  }
  override fun configure() {
    ...
  }
}
然后我使用
属性模块
创建喷油器:

...
val injector = Guice.createInjector(
  PropertiesModule(),
  ...
)
稍后,当我使用注入器获取属性值时,我有多种选择。我可以做到:

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


我了解到,通常应该避免使用
getInstance
。但是我不确定它们之间有什么区别。

如果您刚刚创建了注入器,请使用
getInstance
。否则,请尝试从较窄的注入中获取对象


getBinding
getExistingBinding
有效地用于:

[绑定]是从键(类型和可选注释)到获取类型实例的策略的映射。此接口是内省API的一部分,主要供工具使用

尽管它可能会在某种程度上起作用,但我建议不要使用
getExistingBinding
,因为它具有一种违反直觉的行为,即如果不存在即时绑定,则不创建即时绑定,如中所述:

getBinding(Key)
不同,这不会尝试为未绑定的键创建即时绑定。 此方法是Guice SPI的一部分,供工具和扩展使用

将从图中获取一个
提供程序
,它类似于一个单键注入器,只能从注入器中创建或检索单键实例。可以将其视为创建一个lambda,该lambda为特定键调用
getInstance
,仅此而已

是Injector上最重要的方法,我希望所有Guice应用程序至少调用一次。如果您刚刚创建了注入器,您可能想从中获取一个实例,或者注入对象的
@inject
字段。前者发生在
getInstance
中,后者发生在
getInstance中。在我看来,这是从图形中获取第一个对象的最佳方法

然而,这就是你听到的建议:在第一次调用
getInstance
injectMembers
之后,你可能不应该使用注入器。这是因为Guice中的目标是使独立的组件狭义地表达它们的依赖关系,以便您可以轻松地替换这些依赖关系。这是依赖注入的主要好处。尽管您可以选择将注入器隐藏在静态的某个位置,或者将注入器本身注入到依赖项中,但这会妨碍您准确地知道类的依赖项是什么:使用
注入器
注入,您可以注入世界上的任何东西

为了证明(请原谅我Kotlin缺乏经验):

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()
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.
  }
}