如何使用构造函数参数将 () 注入到 class 中?
How to Inject() into a class with constructor parameters?
我有一个 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"
}
所以,通常的做法是在目标class中@Inject()UsersCollection
。但我不能做类似的事情:
class WebSocketActor @Inject()(out: ActorRef, users: UsersCollection) extends Actor { ... }
因为 actor 的实例在 WebSocketActor
伴随对象中创建:
object WebSocketActor {
def props(out: ActorRef) = Props(new WebSocketActor(out))
}
如何在 WebSocketActor
中使用 UsersCollection
?
您可以创建 actor,Play 会自动注入其依赖项。没问题。 (https://www.playframework.com/documentation/2.6.x/ScalaAkka)
但是在网络套接字的情况下,预期 Props actor,而不是 Actor(或 ActorRef)本身。
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
并将其传递给道具。
简单,我看不出有什么缺点。
我的 play 应用程序中有一个事件处理程序模块,它基本上在应用程序启动时实例化所有参与者。事件处理程序都是演员,所以你可以这样做:
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"
)
}
在模块 i 运行 中,引导程序是这样的:
class EventModule extends ScalaModule with AkkaGuiceSupport {
override def configure(): Unit = {
bind[EventHandlerBootstrap].asEagerSingleton()
}
}
如果您当然不急于盲目地遵循我的方法,您仍然可以排除这样一个事实,即如上所示,guice 完全支持注入您的 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"
}
所以,通常的做法是在目标class中@Inject()UsersCollection
。但我不能做类似的事情:
class WebSocketActor @Inject()(out: ActorRef, users: UsersCollection) extends Actor { ... }
因为 actor 的实例在 WebSocketActor
伴随对象中创建:
object WebSocketActor {
def props(out: ActorRef) = Props(new WebSocketActor(out))
}
如何在 WebSocketActor
中使用 UsersCollection
?
您可以创建 actor,Play 会自动注入其依赖项。没问题。 (https://www.playframework.com/documentation/2.6.x/ScalaAkka)
但是在网络套接字的情况下,预期 Props actor,而不是 Actor(或 ActorRef)本身。
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
并将其传递给道具。
简单,我看不出有什么缺点。
我的 play 应用程序中有一个事件处理程序模块,它基本上在应用程序启动时实例化所有参与者。事件处理程序都是演员,所以你可以这样做:
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"
)
}
在模块 i 运行 中,引导程序是这样的:
class EventModule extends ScalaModule with AkkaGuiceSupport {
override def configure(): Unit = {
bind[EventHandlerBootstrap].asEagerSingleton()
}
}
如果您当然不急于盲目地遵循我的方法,您仍然可以排除这样一个事实,即如上所示,guice 完全支持注入您的 actor 及其依赖项。希望对你有帮助