使用Guice多重绑定和辅助注入为集合成员

时间:2014-10-22 17:59:40

标签: java scala guice

我有一个类PluginManager,它使用Guice多重绑定功能接受Set<Plugin>。但是,PluginManager有一些运行时信息需要传递给Plugin构造函数。

这似乎是Guice辅助注入的完美用例,即我的PluginManager将注入Set<PluginFactory>,其中运行时信息被提供给每个工厂,从而产生所需的{{1}实例。

但我不知道Plugin中使用的语法。多重绑定器Module似乎无法连接addBinding的结果。

我可以创建自己的自定义Factory实现和多绑定,但是有没有办法将multibinder和辅助注入结合起来?

1 个答案:

答案 0 :(得分:2)

我认为这可以为您提供一个完全符合您需求的示例。请注意,scala的multibinder有一个挂起的pull请求,允许您在多个位置创建set binder。

object Test {
  trait Plugin {
    def name(): String
  }

  object Plugin {
    trait Factory[+T <: Plugin] {
      def newPlugin(name: String): T
    }
  }

  case class MyPlugin @Inject() (@Assisted name: String) extends Plugin
  case class OtherPlugin @Inject() (@Assisted name: String) extends Plugin

  class PluginManager @Inject() (pluginFactories: Set[Plugin.Factory[Plugin]]) {
    for (factory <- pluginFactories) {
      println(factory.newPlugin("assisted injection"))
    }
  }

  def main(args: Array[String]): Unit = {
    val injector = Guice.createInjector(new ScalaModule {
      override def configure(): Unit = {
        val plugins = ScalaMultibinder.newSetBinder[Plugin.Factory[Plugin]](binder)
        plugins.addBinding().to[Plugin.Factory[MyPlugin]]
        plugins.addBinding().to[Plugin.Factory[OtherPlugin]]

        bindFactory[Plugin, MyPlugin, Plugin.Factory[MyPlugin]]()
        bindFactory[Plugin, OtherPlugin, Plugin.Factory[OtherPlugin]]()

        bind[PluginManager].asEagerSingleton()
      }

      def bindFactory[I: Manifest, C <: I : Manifest, F: Manifest](): Unit = {
        import net.codingwell.scalaguice._
        install(new FactoryModuleBuilder()
          .implement(typeLiteral[I], typeLiteral[C])
          .build(typeLiteral[F]))
      }
    })
  }
}

根据您想要的风格,您可以做很多事情。例如,您可以制作一个通用的addPlugin方法(当发布更新版本的scala-guice时),如下所示:

val injector = Guice.createInjector(new ScalaModule {
  override def configure(): Unit = {
    bindPlugin[MyPlugin]()
    bindPlugin[OtherPlugin]()

    bind[PluginManager].asEagerSingleton()
  }

  def bindPlugin[T <: Plugin : Manifest](): Unit = {
    val plugins = ScalaMultibinder.newSetBinder[Plugin.Factory[T]](binder)
    plugins.addBinding().to[Plugin.Factory[T]]
    bindFactory[Plugin, T, Plugin.Factory[T]]()
  }

  def bindFactory[I: Manifest, C <: I : Manifest, F: Manifest](): Unit = {
    import net.codingwell.scalaguice._
    install(new FactoryModuleBuilder()
      .implement(typeLiteral[I], typeLiteral[C])
      .build(typeLiteral[F]))
  }
})