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

[亡魂溺海] 提交于 2019-12-06 21:40:52

问题


WebSocket.acceptWithActor instantiates a new Akka actor without making use of Guice.

With Play 2.4, using the injector for my actor was still possible by importing play.api.Play.current.

Snippet from 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))
}

But in Play 2.5, play.api.Play.current is deprecated. How can I still inject ReactiveMongoApi in my actor? What is the recommended way of using an instance of ReactiveMongoApi in my actor?

Here is my code which works with Play 2.4 because my custom actor class ClientActor has access to ReactiveMongoApi through current.injector.instanceOf[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)
  }

}

回答1:


I don't think this is possible. Quoting 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)
  }
}



回答2:


Play 2.5 has built in support for DI.

MidiActor signature needs to be modified as said below.

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

Create new Module and enable in application.conf

play.modules.enabled += MyModule

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

Change your controller as below

@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)
  }

}


来源:https://stackoverflow.com/questions/45774470/websocket-acceptwithactor-and-inject-in-the-actor-play-2-5

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!