将构造函数参数传递给 Play 管理的 Actor
Passing a constructor argument to a Play managed Actor
我有一个主管和一个工人演员。工作人员调用服务。所有这些都由 Play(/Guice) 管理。
这里是代码的简化:
class SupervisorActor @Inject()(workerFactory: WorkerActor.Factory, serviceA: AService)
extends Actor
with InjectedActorSupport {
override def receive: Receive = {
case message => injectedChild(workerFactory(serviceA), "childActorName").forward(message)
}
}
class WorkerActor @Inject()(serviceA: AService) extends Actor {
override def receive: Receive = {
case _ => println(serviceA.getMessage())
}
}
object WorkerActor {
trait Factory {
def apply(serviceA: AService): Actor
}
}
@ImplementedBy(classOf[AServiceImpl])
trait AService {
def getMessage(): String
}
class AServiceImpl @Inject()(configuration: Configuration) extends AService {
override def getMessage(): String = configuration.get[String]("id1")
}
Module.scala(configure
方法):
bindActor[SupervisorActor]("supervisor")
bindActorFactory[WorkerActor, WorkerActor.Factory]
一切正常。到目前为止,每个 class.
都有一个实例
现在,AServiceImpl.getMessage()
需要查找动态字符串(不只是每次 "id1")。所以改成这样:
class AServiceImpl @Inject()(configuration: Configuration, propertyId: String) extends AService {
override def getMessage(): String = configuration.get[String](propertyId)
}
并从 trait AService
中删除了 @ImplementedBy(classOf[AServiceImpl])
。
我们的想法是实例化 supervisor、worker 和 service 的 2 个实例,并将它们连接在一起 Module.scala。所以我从 Module.scala:
开始
val aServive: AService = new AServiceImpl(configuration, "id1")
现在的挑战是将这个实例注入主管。
感谢对这些的任何帮助:
- 当注入器仍在构建中时,如何在 configure() (Module.scala) 中访问 Guice managed WorkerActor.Factory?
- 我尝试使用带有 WorkerActor.Factory 作为参数的 @Provides 方法。但是 bindActor() 调用只允许在 configure() 中使用。不在@Provides 方法中。
- 如何让 Play 注入
workerFactory: WorkerActor.Factory
但提供我自己的 AService
?据我所知,bindActor(...)
似乎不支持这个。
编辑:
我的解决方案基于以下 Renato 的回答以供将来使用:
我必须为每个需要的 actor(对象图)实例实现一个 ActorRef Provider。像这样:
class PropertyId1SupervisorActorProvider @Inject()(configuration: Configuration,
workerFactory: WorkerActor.Factory,
actorSystem: ActorSystem)
extends Provider[ActorRef] {
override def get(): ActorRef = {
val aService: AService = new AServiceImpl(configuration, "propertyId1")
actorSystem.actorOf(Props(classOf[SupervisorActor], workerFactory, aService))
}
}
然后在Module.scala中绑定这个提供者:
bind(classOf[ActorRef])
.annotatedWith(Names.named("propertyId1Actor"))
.toProvider(classOf[PropertyId1SupervisorActorProvider])
这确实需要一些工作才能让另一个实例运行。但这是我目前拥有的最佳解决方案。如果有改进的建议,我会洗耳恭听。
我认为您可以通过使用一个提供程序来简化它,该提供程序可以完成所有工作,而不必过多依赖任何 Guice 连接。提供者应该 return 您想要注入系统其他部分的 Actor。 Actor 下的所有图形都可以而且应该隐藏,换句话说,不要暴露给 DI。
只需为 actor 创建一个提供者,注入 ActorSystem
和 Configuration
,这样您就可以创建 actor 并构建服务实例。
由于您需要该 actor 的两个实例,因此需要为它们取不同的名称,并在 Guice 中用不同的名称绑定它们。
我有一个主管和一个工人演员。工作人员调用服务。所有这些都由 Play(/Guice) 管理。
这里是代码的简化:
class SupervisorActor @Inject()(workerFactory: WorkerActor.Factory, serviceA: AService)
extends Actor
with InjectedActorSupport {
override def receive: Receive = {
case message => injectedChild(workerFactory(serviceA), "childActorName").forward(message)
}
}
class WorkerActor @Inject()(serviceA: AService) extends Actor {
override def receive: Receive = {
case _ => println(serviceA.getMessage())
}
}
object WorkerActor {
trait Factory {
def apply(serviceA: AService): Actor
}
}
@ImplementedBy(classOf[AServiceImpl])
trait AService {
def getMessage(): String
}
class AServiceImpl @Inject()(configuration: Configuration) extends AService {
override def getMessage(): String = configuration.get[String]("id1")
}
Module.scala(configure
方法):
bindActor[SupervisorActor]("supervisor")
bindActorFactory[WorkerActor, WorkerActor.Factory]
一切正常。到目前为止,每个 class.
都有一个实例现在,AServiceImpl.getMessage()
需要查找动态字符串(不只是每次 "id1")。所以改成这样:
class AServiceImpl @Inject()(configuration: Configuration, propertyId: String) extends AService {
override def getMessage(): String = configuration.get[String](propertyId)
}
并从 trait AService
中删除了 @ImplementedBy(classOf[AServiceImpl])
。
我们的想法是实例化 supervisor、worker 和 service 的 2 个实例,并将它们连接在一起 Module.scala。所以我从 Module.scala:
开始val aServive: AService = new AServiceImpl(configuration, "id1")
现在的挑战是将这个实例注入主管。
感谢对这些的任何帮助:
- 当注入器仍在构建中时,如何在 configure() (Module.scala) 中访问 Guice managed WorkerActor.Factory?
- 我尝试使用带有 WorkerActor.Factory 作为参数的 @Provides 方法。但是 bindActor() 调用只允许在 configure() 中使用。不在@Provides 方法中。
- 如何让 Play 注入
workerFactory: WorkerActor.Factory
但提供我自己的AService
?据我所知,bindActor(...)
似乎不支持这个。
编辑:
我的解决方案基于以下 Renato 的回答以供将来使用:
我必须为每个需要的 actor(对象图)实例实现一个 ActorRef Provider。像这样:
class PropertyId1SupervisorActorProvider @Inject()(configuration: Configuration,
workerFactory: WorkerActor.Factory,
actorSystem: ActorSystem)
extends Provider[ActorRef] {
override def get(): ActorRef = {
val aService: AService = new AServiceImpl(configuration, "propertyId1")
actorSystem.actorOf(Props(classOf[SupervisorActor], workerFactory, aService))
}
}
然后在Module.scala中绑定这个提供者:
bind(classOf[ActorRef])
.annotatedWith(Names.named("propertyId1Actor"))
.toProvider(classOf[PropertyId1SupervisorActorProvider])
这确实需要一些工作才能让另一个实例运行。但这是我目前拥有的最佳解决方案。如果有改进的建议,我会洗耳恭听。
我认为您可以通过使用一个提供程序来简化它,该提供程序可以完成所有工作,而不必过多依赖任何 Guice 连接。提供者应该 return 您想要注入系统其他部分的 Actor。 Actor 下的所有图形都可以而且应该隐藏,换句话说,不要暴露给 DI。
只需为 actor 创建一个提供者,注入 ActorSystem
和 Configuration
,这样您就可以创建 actor 并构建服务实例。
由于您需要该 actor 的两个实例,因此需要为它们取不同的名称,并在 Guice 中用不同的名称绑定它们。