Actor는 내부에서 액터를 생성할 수도 있다. 간단한 예로 다음과 같은 코드가 될 수 있다.
object Child {
case object Call
}
class Child extends Actor {
import Child._
override def receive: Receive =
{
case Call => println("the child has been called")
}
}
object Parent {
case object CreateChild
case object Print
}
class Parent extends Actor {
import Parent._
import Child._
override def receive: Receive = {
case CreateChild =>
val child = context.actorOf(Props[Child], "child")
context.become(withChild(child))
case Print =>
println("I have no child")
}
private def withChild(childActor: ActorRef): Receive = {
case Print =>
println("I have a child")
childActor ! Call
}
}
위의 코드를 작성하고 main에서 다음과 같은 메시지를 보낸다면 결과는 다음과 같다.
parent ! Print
parent ! CreateChild
parent ! Print
위의 코드를 실행하면 밑과 같이 된다.
부모 액터에서 생성한 자식 액터가 제대로 생성되었으며, 자식 액터에 메시지도 제대로 보내진다는 것을 알 수 있다. 한 가지 주의해야할 점은 부모 액터 역시 자식 액터에 접근을 못하고 proxy 역할인 ActoreRef로 메시지를 보내야 한다는 점이다.
그렇다면 여러 자식 액터를 만드려면 어떻게 할까?
object Child {
case object Call
}
class Child extends Actor {
import Child._
override def receive: Receive =
{
case Call => println(s"[$self.path] the child has been called")
}
}
object Parent {
case class CreateChildren(nChildren:Int)
case object Print
}
class Parent extends Actor {
import Parent._
import Child._
override def receive: Receive = {
case CreateChildren(nChildren: Int) =>
val children = (0 until nChildren).map(index => context.actorOf(Props[Child], s"child$index"))
context.become(withChildren(children))
case Print =>
println("I have no child")
}
private def withChildren(children: IndexedSeq[ActorRef]): Receive = {
case Print =>
println("I have children")
children.foreach(child => child ! Call)
}
}
여러 개의 자식 액터를 명확하게 확인하기 위해 자식 액터가 호출되었을 때 self.path
를 호출하도록 하였다. 위의 코드를 다음과 같은 코드로 실행하면 어떨까?
val system = ActorSystem("system")
val parent = system.actorOf(Props[Parent], "parent")
parent ! Print
parent ! CreateChildren(5)
parent ! Print
위는 5개의 자식 액터를 생성하기 위한 코드이다. 위의 코드를 실행하면
위와 같이 되는데, child 0부터 child 4가 제대로 생성되는 것을 알 수 있다.