Play Framework,Akka,Guice:如何在控制器内部使用Guice创建一个actor的多个实例(具有依赖项)? [英] Play Framework, Akka, Guice : How to create multiple instances of an actor (which has dependencies) with Guice inside controller?

查看:220
本文介绍了Play Framework,Akka,Guice:如何在控制器内部使用Guice创建一个actor的多个实例(具有依赖项)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

播放框架文档中有一个示例( https://www.playframework. com/documentation/2.6.x/ScalaAkka )说明如何将actor(具有要注入的依赖项)注入控制器:

There is an example in play framework doc (https://www.playframework.com/documentation/2.6.x/ScalaAkka) that explains how to inject actor (which has dependencies to be injected) into controller:

@Singleton
class Application @Inject() 
(@Named("configured-actor") configuredActor: ActorRef)
(implicit ec: ExecutionContext) extends Controller {

      implicit val timeout: Timeout = 5.seconds

      def getConfig = Action.async {
        (configuredActor ? GetConfig).mapTo[String].map { message =>
          Ok(message)
        }
      }
    }

但是据我了解,它会创建一个actor的单个实例(例如singleton).

But as I understand, it creates a single instance of the actor (e.g., singleton).

我需要在控制器内创建configuredActor的多个实例.

I need to create multiple instances of configuredActor inside the controller.

还有一个示例演示了如何从父actor创建子actor(具有要注入的依赖项)实例

There is also an example which demonstrates how to create child actors (which has dependencies to be injected) instances from parent actor

object ParentActor {
  case class GetChild(key: String)
}

class ParentActor @Inject() (
    childFactory: ConfiguredChildActor.Factory
) extends Actor with InjectedActorSupport {
  import ParentActor._

  def receive = {
    case GetChild(key: String) =>
      val child: ActorRef = injectedChild(childFactory(key), key)
      sender() ! child
  }
}

我试图在控制器内部应用此技术,但是injectedChild(childFactory(key), key)需要(隐式)actor上下文

I've tried to apply this technique inside controller, but injectedChild(childFactory(key), key) requires (implicitly) actor context

def injectedChild(create: => Actor, name: String, props: Props => Props = identity)(implicit context: ActorContext): ActorRef = ...

但是我需要从ActorSysem(例如/user)创建这个actor.

But I need to create this actor from ActorSysem (e.g. /user).

(我本来想获得/user actor的上下文,但是如何?这是正确的吗?)

(I thought to get the context of /user actor, but how? is that correct?)

在父角色外部(例如,在控制器内部)使用Guice创建角色的多个实例的正确方法是什么?

What is a proper way to create multiple instances of an actor with Guice outside parent actor (for example, inside controller)?

推荐答案

我认为没有从演员外部获取ActorContext的方法,但是如果您想从/user演员创建子演员,可以直接system.actorOf做.

I don't think there is a way of obtaining the ActorContext from outside of an actor, but if you like to create child actors from the /user actor you could do directly system.actorOf.

问题就像您说的那样,InjectedActorSupport需要一个ActorContext. 但是,如果您看一下特质,那就没什么花哨的了,只是

The problem is like you said, that InjectedActorSupport needs an ActorContext. But if you look the trait, it doesn't do anything fancy, just

  def injectedChild(create: => Actor, name: String, props: Props => Props = identity)(implicit context: ActorContext): ActorRef = {
    context.actorOf(props(Props(create)), name)
  }

因此,解决方案是扩展特征并添加一个接收ActorSystem而不是ActorContext的方法.

So, the solution is to extend the trait and add a method that receives the ActorSystem instead of the ActorContext.

  def injectedChild2(create: => Actor, name: String, props: Props => Props = identity)(implicit system: ActorSystem): ActorRef = {
    system.actorOf(props(Props(create)), name)
  }

实际上,您甚至可以直接将方法添加到控制器中,但是如果要在多个控制器中执行此操作将不方便.

In fact, you could even add the method to the controller directly but it is not convenient if you want to do this in multiples controllers.

更新:

尽管从技术上讲这是正确的,但我(正确地)认为这是缺乏接收ActorSystem的方法的目的.

although this is technically correct I assumed (correctly) that the lack of a method that receives an ActorSystem was intended.

因此,我已经向Play开发者团队提出了要求,詹姆斯·罗珀(James Roper)回答:

So, I've asked to the play dev team and James Roper has answered:

之所以这样做,是因为通常不直接从actor系统外部创建很多actor,因为您不能监督他们-也就是说,您不能说应该做什么它们崩溃时会发生(应该停止,重新启动,升级等)吗?在所有我想从控制器中创建角色的场景中,对于我来说,这样做总是更好的设计,而不是这样做,而是向另一个经理角色发送消息以创建子角色.例如,当您执行此操作时,它将为您提供更大的灵活性,例如,假设将来您有一个要求,即当用户重新提交相同的操作时,它不应启动新的参与者但应连接到现有演员.如果您有经理角色,这很容易做到,则可以自动检查经理演员是否已经有该操作的子对象,并在必要时创建一个新的子对象.如果没有,那是不可能的.然后在将来,您将转移到多节点设置,并且您可能会决定在整个群集上分派参与者-再次,非常简单,如果您使用的是管理者参与者,因为您要做的就是用替换为管理者参与者.集群分片,或将集群一致的哈希路由器放置在管理器的前面,但是如果直接从控制器创建参与者,则不可能.

The reason for this is that it's generally not good practice to create many actors directly from outside the actor system, because you can't supervise them - that is, you can't say what should happen when they crash (should they be stopped, restarted, escalated etc?). In all the scenarios where I've wanted to create an actor from a controller, it's always ended up being a better design for me to not do that, rather, to send a message to another manager actor to create the child actor. When you do this, it gives you a lot more flexibility in future, for example, lets say in future you have a requirement that when a user resubmits the same operation, it shouldn't start a new actor but should connect to the existing actor. If you have a manager actor, that's very easy to do, you can atomically check if the manager actor has a child for that operation already, and create a new child if necessary. If not, it's not possible. And then in future you move to a multi node setup, and you might decide to shard your actors across a cluster - again, very easy if you were using a manager actor because all you need to do is replace the manager actor with cluster sharding, or put a clustered consistent hashing router in front of your manager, but if creating actors directly from the controller, not possible.

这篇关于Play Framework,Akka,Guice:如何在控制器内部使用Guice创建一个actor的多个实例(具有依赖项)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆