使用 Scala Guice 将特征绑定到对象

mat*_*wrk 5 dependency-injection scala guice

这将是一个关于如何让绑定工作的问题,但在清理我准备发布的示例时,我实际上已经设法让它工作 - 问题是我不知道为什么会这样:

import org.specs2.mutable._
import com.google.inject.{ Inject, Module, Binder, Guice }
import net.codingwell.scalaguice.ScalaModule

object InjectorSpec extends Specification {
  val injector = Guice.createInjector(new ScalaModule() {
    def configure() {
      bind[Message].toInstance(MessageImpl)
      bind[MessageService.type].toInstance(MessageService) // This line makes it work?
    }
  })

  trait Message {
    val body: String
  }

  object MessageImpl extends Message {
    val body: String = "Hello!"
  }

  object MessageService {
    @Inject
    val message: Message = null

    def get = message.body
  }

  "MessageService" should {
    "Inject Message Implementation" in {
      MessageService.get mustEqual "Hello!"
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

最初我只是绑定要注入的类型(为消息注入 MessageImpl)。在此过程中的某个地方,我选择了用于服务的第二个绑定,它没有被注入(所以我不明白需要绑定)。任何人都可以解释这里发生了什么,这是否是正确的进行方式?

Dan*_*tin 3

所以问题是 guice 不会搜索你的程序并找到你@Inject在任何地方加载的任何类中的所有点。相反,需要为它提供一些路径来查找您希望其注入内容的对象。一般来说,这是通过使用 Guice 的方式来解决的,因为标准模式是:

val injector = Guice.createInjector(/* stuff */)
val main = injector.getInstance(classOf[Main])
main.mainMethod()
Run Code Online (Sandbox Code Playgroud)

MainGuice在您要求它 make/get的实例上执行注入,并递归地对@Inject编辑到 中的所有内容执行注入main

就您而言,这些陈述之一也有效;我说“之一”,因为虽然我可以准确地告诉你如何注入到 java 中,但我并不完全清楚 scala 编译器如何将 scala 伴随对象编译成 java 类。(也就是说,我不知道message最终是否在java级别成为被调用类上的静态变量MessageService$或实例变量,MessageService$通过某种线程安全的单例模式仅实例化一次)

requestInjection(MessageService)
requestStaticInjection(MessageService.type)
Run Code Online (Sandbox Code Playgroud)

该语句起作用的原因toInstance是 Guice 自动toInstance对创建注入器时传递给的所有对象执行注入。(.asEagerSingleton当注入器启动时,绑定的东西也会对其执行注入,如果您创建“生产模式”注入器,则所有绑定为单例的东西也会执行注入)

  • 好吧,理想情况下,您仅引用“injector”一次,为主类仅调用一次“getInstance”,然后所有内容都从那里注入。Scala 伴生对象把事情搞砸了一点,因为从 java 的角度来看,它们是在 Guice 之外创建的这些单例对象。现在,这很好,但是当你拥有这些 Guice 没有创建的对象,而你希望 Guice 向其中注入东西时,麻烦就来了。我不喜欢 scala-guice 风格(我所有的 Guice 经验都是在 java 中),但我认为解决方案是永远不要将“@Inject”注入伴随对象。 (2认同)