2017-09-16 8 views
2

J'ai un contrôleur WebSocket qui crée par gestionnaire d'acteur de connexion:Comment Injecter() dans une classe avec les paramètres du constructeur?

class WebSocketController @Inject()(cc: ControllerComponents)(implicit exc: ExecutionContext) { 
    def socket: WebSocket = WebSocket.accept[JsValue, JsValue] { request => 
    ActorFlow.actorRef { out => // Flow that is handled by an actor from 'out' ref 
     WebSocketActor.props(out) // Create an actor for new connected WebSocket 
    } 
    } 
} 

Et dans le gestionnaire d'acteur que je dois travailler avec ReactiveMongo:

trait ModelDAO extends MongoController with ReactiveMongoComponents { 
    val collectionName: String 
    ... 
} 
class UsersCollection @Inject()(val cc: ControllerComponents, 
           val reactiveMongoApi: ReactiveMongoApi, 
           val executionContext: ExecutionContext, 
           val materializer: Materializer) 
    extends AbstractController(cc) with ModelDAO { 
    val collectionName: String = "users" 
} 

Ainsi, la manière habituelle est de @Inject (UsersCollection dans la classe cible. Mais je ne peux pas faire quelque chose comme:

class WebSocketActor @Inject()(out: ActorRef, users: UsersCollection) extends Actor { ... } 

Parce que les instances de l'acteur crée à l'intérieur WebSocketActor objet compagnon:

object WebSocketActor { 
    def props(out: ActorRef) = Props(new WebSocketActor(out)) 
} 

Comment utiliser UsersCollection à l'intérieur du WebSocketActor?

+0

Est-ce que cela peut être lié? https://stackoverflow.com/q/45774470/1080523 – rethab

Répondre

1

Vous pouvez créer l'acteur dont les dépendances seront automatiquement injectées par Play. Aucun problème. (https://www.playframework.com/documentation/2.6.x/ScalaAkka)

Mais en cas de prises web, Props de l'acteur est attendu, mais pas Acteur (ou ActorRef) lui-même.

ActorFlow.actorRef { out => // Flow that is handled by an actor from 'out' ref 
    WebSocketActor.props(out) // <- ACTOR IS NOT CREATED HERE, WE RETURN PROPS 
} 

Donc il n'y a aucun moyen de le faire automatiquement dans ce cas (au moins je ne l'ai pas trouvé). Vous pouvez faire passer UsersCollection manuellement.

class WebSocketController @Inject()(cc: ControllerComponents, usersCollection: UsersCollection)(implicit exc: ExecutionContext) { 
    def socket: WebSocket = WebSocket.accept[JsValue, JsValue] { request => 
    ActorFlow.actorRef { out => // Flow that is handled by an actor from 'out' ref 
     WebSocketActor.props(out, usersCollection) //<- ACTOR IS NOT CREATED HERE, WE RETURN PROPS 
    } 
    } 
} 

remarqué que je UsersCollection injecté dans WebSocketController et le transmettre à des accessoires.

Simple et je ne vois aucun inconvénient.

+0

Je suppose que la question est plutôt comment injecter un 'ActorRef' – cchantep

+0

S'il vous plaît regardez la [capture d'écran] (https://snag.gy/X0DguQ.jpg) –

+0

Merci pour la réponse, le désavantage est dans ceux que j'ai plus de collections (utilisateurs, tableaux etc.). Est-il normal de tout passer manuellement à l'acteur? –

0

J'ai un module de gestionnaire d'événements dans mon application de jeu qui instancie fondamentalement tous les acteurs au démarrage de l'application. gestionnaires d'événements sont tous les acteurs pour que vous puissiez le faire comme ceci:

class EventHandlerBootstrap @Inject() (system: ActorSystem, app: Application) { 
    EventHandlerBootstrap.handlers.foreach { 
    case (h, n) => system.actorOf(Props(app.injector.instanceOf(h)), n) 
    } 
} 

//These Class[_ <: EventHandler] are classes of user defined actors each with their own 
// dependencies which guice will take care of automattically. 
object EventHandlerBootstrap { 
    val handlers: Map[Class[_ <: EventHandler], String] = Map(
    classOf[UserRegisteredHandler] -> "user-registered-handler", 
    classOf[CustomerOrderCreatedHandler] -> "customer-order-created-handler", 
    classOf[DisputeClosedHandler] -> "dispute-closed-handler", 
    classOf[Throttle] -> "throttle" 
) 
} 

et à l'intérieur du module i exécuter le programme d'amorçage comme ceci:

class EventModule extends ScalaModule with AkkaGuiceSupport { 

    override def configure(): Unit = { 
    bind[EventHandlerBootstrap].asEagerSingleton() 
    } 
} 

si vous n'êtes ofcourse pas désireux de suivre aveuglément ma recette vous pouvez toujours supprimer le fait que l'injection de vos acteurs et de leurs dépendances est entièrement supportée par guice comme indiqué ci-dessus. J'espère que ça va aider