Actor 中的 WebSocket.acceptWithActor 和 @Inject() (播放 2.5)

WebSocket.acceptWithActor and @Inject() in the Actor (Play 2.5)

WebSocket.acceptWithActor 在不使用 Guice 的情况下实例化一个新的 Akka actor。

使用 Play 2.4,仍然可以通过导入 play.api.Play.current.

为我的演员使用注入器

来自 ReactiveMongo documentation 的片段:

import scala.concurrent.Future

import play.api.Play.current // should be deprecated in favor of DI
import play.api.libs.concurrent.Execution.Implicits.defaultContext

import play.modules.reactivemongo.ReactiveMongoApi
import play.modules.reactivemongo.json.collection.JSONCollection

object Foo {
  lazy val reactiveMongoApi = current.injector.instanceOf[ReactiveMongoApi]

  def collection(name: String): Future[JSONCollection] =
    reactiveMongoApi.database.map(_.collection[JSONCollection](name))
}

但在 Play 2.5 中,play.api.Play.current 已被弃用。 我怎样才能在我的 actor 中注入 ReactiveMongoApi?在我的演员中使用 ReactiveMongoApi 实例的推荐方法是什么?

这是我的适用于 Play 2.4 的代码,因为我的自定义演员 class ClientActor 可以通过 current.injector.instanceOf[ReactiveMongoApi]:

访问 ReactiveMongoApi
@Singleton
class Application @Inject() (system: ActorSystem) extends Controller {

  val midiDiscoveryActor = system.actorOf(MidiDiscoveryActor.props, "midi-discovery-actor")
  val midiActor = system.actorOf(MidiActor.props(midiDiscoveryActor), "midi-actor")

  def index(page: String) = Action {
    Ok(views.html.index(page))
  }

  def bidirectional = WebSocket.acceptWithActor[JsValue, JsValue] { request => out =>
    ClientActor.props(out, midiActor, midiDiscoveryActor)
  }

}

我认为这是不可能的。引用 James Roper:

The helpers that Play provides for dependency injecting actors are suited for a limited number of use cases. Though, the helpers are really just very thin wrappers over some common requirements - they're not needed at all. In the case Play's WebSocket actor support, the thing is, generally you want to manually instantiate the actor since you have to somehow pass it the out ActorRef. So, you can either do this using Guice assisted inject, and define a factor interface that takes the out actor ref (and whatever other arguments you want to pass to it), or simply instantiate it manually, passing dependencies from the controller to the actor, for example:

class MyController @Inject() (myDep: MyDep) extends Controller {
  def socket = WebSocket.acceptWithActor[String, String] { request => out =>
    MyWebSocketActor.props(out, myDep)
  }
}

Play 2.5 内置了对 DI 的支持。

MidiActor 签名需要修改如下。

class MidiActor@Inject() (configuration: Configuration,  @Named("midi-discovery-actor") midiDiscoveryActor: ActorRef) extends Actor with InjectedActorSupport{
.......
}

创建新模块并在 application.conf

中启用
play.modules.enabled += MyModule

class MyModule extends AbstractModule with AkkaGuiceSupport {
  def configure = {
    bindActor[MidiDiscoveryActor]("midi-discovery-actor")
    bindActor[MidiActor]("midi-actor")
  }
}

如下更改您的控制器

@Singleton
class Application @Inject() (system: ActorSystem,@Named("midi-actor") midiActor: ActorRef,
@Named("midi-discovery-actor") midiDiscoveryActor: ActorRef) (implicit ec: ExecutionContext)  extends Controller {

  def index(page: String) = Action {
    Ok(views.html.index(page))
  }

  def bidirectional = WebSocket.acceptWithActor[JsValue, JsValue] { request => out =>
    ClientActor.props(out, midiActor, midiDiscoveryActor)
  }

}