我想实现一个 Guice 模块,它将适配器绑定到命名参数,但要创建这个适配器,它需要实例化另一个类,该类也需要注入参数。
下面是 Scala 中的示例:
trait Service
class UserService @Inject()(@Named(value = "foo") foo: String) extends Service
trait Adapter
class AdapterImpl(service: Service) extends Adapter
class AdapterRef(val adapter: Adapter)
class Module extends AbstractModule {
override def configure(): Unit = {
val fooValue = "bar"
bind(classOf[String])
.annotatedWith(Names.named("foo"))
.toInstance(fooValue)
val userService = new UserService(fooValue) //It should be instantiated by Guice somehow
bind(classOf[AdapterRef])
.annotatedWith(Names.named("userService"))
.toInstance(new AdapterRef(new AdapterImpl(userService))) //Thats kinda ok
}
}
有人可以指出我正确的方向吗?
谢谢
加博尔
可以在模块中使用 Provision 方法,该方法允许您删除绑定。这是我在 Scala 所做的最大努力,所以如果语法不正确,请告诉我。
@Provides() @Singleton() def provideAdapterRef(service: Service): AdapterRef = {
return new AdapterRef(new AdapterImpl(service))
}
请注意使用单例来模仿您的示例使用toInstance
。如果您不需要它始终提供相同的实例,我建议您删除范围并让它每次创建一个新范围。
另一种解决方案是使用提供程序。这要求您在模块中保留绑定的修改版本并创建一个额外的类,但如果提供程序更复杂,这可能是一个更干净的解决方案。
//Can inject UserService as well, or provide annotations to configure which
//implementation of Service you get if you have more than one.
class UserServiceProvider @Inject()(service: Service) extends Provider[AdapterRef] {
override def get(): AdapterRef {
return new AdapterRef(new AdapterImpl(service))
}
}
然后,您可以将模块中的绑定更改为
bind(classOf[AdapterRef])
.annotatedWith(Names.named("userService"))
.toProvider(classOf[UserServiceProvider])
.in(classOf[Singleton])
此处请注意如何使用in(Singleton)
来复制toInstance
行为。