如何使用构造函数参数将()注入到类中?

时间:2017-09-16 10:39:01

标签: scala dependency-injection playframework actor

我有一个WebSocket控制器,它创建每个连接actor处理程序:

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

在actor处理程序中我需要使用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"
}

因此,通常的方法是在目标类中使用@Inject()UsersCollection。但我无法做到这样的事情:

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

因为actor的实例在WebSocketActor个伴随对象中创建:

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

如何在UsersCollection内使用WebSocketActor

2 个答案:

答案 0 :(得分:1)

您可以创建演员,Play会自动注入依赖项。没问题。 (https://www.playframework.com/documentation/2.6.x/ScalaAkka

如果是网络套接字,则需要演员的道具,而不是演员(或演员参考)本身。

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

所以在这种情况下没有办法自动完成(至少我没有找到它)。

您可以做的是手动传递UsersCollection

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

注意到我已将UsersCollection注入WebSocketController并将其传递给道具。

简单,我认为没有任何不利之处。

答案 1 :(得分:0)

我的Play应用程序中有一个事件处理程序模块,它基本上在应用程序启动时实例化所有actor。事件处理程序都是演员,所以你可以这样做:

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

在模块内部我运行这样的引导程序:

class EventModule extends ScalaModule with AkkaGuiceSupport {

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

如果你当然不急于盲目遵循我的食谱,你仍然可以看出注入你的演员及其依赖关系的事实完全由guice支持,如上所示。希望它能帮助