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