未为注入的 Akka RouterActor 调用构造函数和 preStart/postStop 钩子
Constructor and preStart/postStop hooks NOT invoked for injected Akka RouterActor
我正在尝试 Play Framework (Scala) 中的一些示例。我正在将一个演员注入控制器。
配置
- Java (1.8.0_144)
- Scala (2.12.3)
- 播放 (2.6.5)
我有以下代码:
示例控制器
class ExampleController @Inject() (
controllerComponents: ControllerComponents,
@Named("injected-router") injectedRouterActor: ActorRef,
@Named("injected") injectedActor: ActorRef)
extends AbstractController(controllerComponents) {
def alive = Action {
injectedActor ! "Hi from Example"
injectedRouterActor ! "Hi From Example to Router"
Ok("Alive")
}
}
InjectedActor
class InjectedActor extends Actor {
val name = s"IA-${self.path}-${System.nanoTime}"
println(s"constructor: $name")
def receive = {
case m => println(s"$name received: $m")
}
override def preStart() = {
println(s"preStart: $name")
super.preStart()
}
}
InjectedRouterActor
class InjectedRouterActor extends Actor {
val name = s"IRA-${self.path}-${System.nanoTime}"
println(s"constructor: $name")
def receive = {
case m => println(s"$name received: $m")
}
override def preStart() = {
println(s"preStart: $name")
super.preStart()
}
}
儿童演员
class ChildActor extends Actor {
val name = s"CH-${self.path}-${System.nanoTime}"
println(s"constructor: $name")
def receive = {
case m => println(s"$name received: $m")
}
}
模块
class BindingModule extends AbstractModule with AkkaGuiceSupport {
def configure = {
bindActor[InjectedActor]("injected")
bindActor[InjectedRouterActor]("injected-router", _ => RoundRobinPool(5).props(Props[ChildActor]))
}
}
当我 运行 执行此操作并点击 alive 的路由时,我在控制台上看到所有参与者的 printlns , 除了 InjectedRouterActor.
无法理解为什么?感谢任何帮助。
谢谢
在 Akka 中,路由器是您未显式实现的特殊实现参与者。
在您的示例中,RoundRobinPool(5).props(Props[ChildActor])
创建了 Props
,这将创建循环池路由器,路由是 ChildActor
类型的参与者。你真的不需要 InjectedRouterActor
。如果你想根据配置创建路由器,你可能仍然想要它(参见 Akka docs 中的示例)。
如果您查看 ActorRefProvider
的源代码,当您使用 Guice 助手时创建角色
class ActorRefProvider[T <: Actor: ClassTag](name: String, props: Props => Props) extends Provider[ActorRef] {
@Inject private var actorSystem: ActorSystem = _
@Inject private var injector: Injector = _
lazy val get = {
val creation = Props(injector.instanceOf[T])
actorSystem.actorOf(props(creation), name)
}
}
你可以看到它创建了默认值 Props
从注入器获取 InjectedRouterActor
的实例(类型信息作为 T
类型参数传递)但是,因为你提供props
作为忽略函数参数 (_ => RoundRobinPool(5).props(Props[ChildActor])
) 的函数,它只会忽略 creation
变量。此外 injector.instanceOf[T]
作为别名参数传递给 Props#apply
,因此不会立即调用它,因此不会创建您的 InjectedRouterActor
。
您可以手动创建它,而不是在 configure
中为路由器角色创建绑定:
@Provides
@Named("injected-router")
@Singleton
def routerProvider(system: ActorSystem): ActorRef = {
system.actorOf(RoundRobinPool(5).props(Props[ChildActor]), name = "injected-router")
}
我正在尝试 Play Framework (Scala) 中的一些示例。我正在将一个演员注入控制器。
配置
- Java (1.8.0_144)
- Scala (2.12.3)
- 播放 (2.6.5)
我有以下代码:
示例控制器
class ExampleController @Inject() (
controllerComponents: ControllerComponents,
@Named("injected-router") injectedRouterActor: ActorRef,
@Named("injected") injectedActor: ActorRef)
extends AbstractController(controllerComponents) {
def alive = Action {
injectedActor ! "Hi from Example"
injectedRouterActor ! "Hi From Example to Router"
Ok("Alive")
}
}
InjectedActor
class InjectedActor extends Actor {
val name = s"IA-${self.path}-${System.nanoTime}"
println(s"constructor: $name")
def receive = {
case m => println(s"$name received: $m")
}
override def preStart() = {
println(s"preStart: $name")
super.preStart()
}
}
InjectedRouterActor
class InjectedRouterActor extends Actor {
val name = s"IRA-${self.path}-${System.nanoTime}"
println(s"constructor: $name")
def receive = {
case m => println(s"$name received: $m")
}
override def preStart() = {
println(s"preStart: $name")
super.preStart()
}
}
儿童演员
class ChildActor extends Actor {
val name = s"CH-${self.path}-${System.nanoTime}"
println(s"constructor: $name")
def receive = {
case m => println(s"$name received: $m")
}
}
模块
class BindingModule extends AbstractModule with AkkaGuiceSupport {
def configure = {
bindActor[InjectedActor]("injected")
bindActor[InjectedRouterActor]("injected-router", _ => RoundRobinPool(5).props(Props[ChildActor]))
}
}
当我 运行 执行此操作并点击 alive 的路由时,我在控制台上看到所有参与者的 printlns , 除了 InjectedRouterActor.
无法理解为什么?感谢任何帮助。
谢谢
在 Akka 中,路由器是您未显式实现的特殊实现参与者。
在您的示例中,RoundRobinPool(5).props(Props[ChildActor])
创建了 Props
,这将创建循环池路由器,路由是 ChildActor
类型的参与者。你真的不需要 InjectedRouterActor
。如果你想根据配置创建路由器,你可能仍然想要它(参见 Akka docs 中的示例)。
如果您查看 ActorRefProvider
的源代码,当您使用 Guice 助手时创建角色
class ActorRefProvider[T <: Actor: ClassTag](name: String, props: Props => Props) extends Provider[ActorRef] {
@Inject private var actorSystem: ActorSystem = _
@Inject private var injector: Injector = _
lazy val get = {
val creation = Props(injector.instanceOf[T])
actorSystem.actorOf(props(creation), name)
}
}
你可以看到它创建了默认值 Props
从注入器获取 InjectedRouterActor
的实例(类型信息作为 T
类型参数传递)但是,因为你提供props
作为忽略函数参数 (_ => RoundRobinPool(5).props(Props[ChildActor])
) 的函数,它只会忽略 creation
变量。此外 injector.instanceOf[T]
作为别名参数传递给 Props#apply
,因此不会立即调用它,因此不会创建您的 InjectedRouterActor
。
您可以手动创建它,而不是在 configure
中为路由器角色创建绑定:
@Provides
@Named("injected-router")
@Singleton
def routerProvider(system: ActorSystem): ActorRef = {
system.actorOf(RoundRobinPool(5).props(Props[ChildActor]), name = "injected-router")
}