如何使用构造函数参数将 () 注入到 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 及其依赖项。希望对你有帮助