Hello everyone, so before starting this part of the blog I want to ask a question. How do we create subordinate Actors? (Akka actor and actor child)We have already worked on the Actor System and we have also successfully created some of the actors. If you want to learn the basics of creating Akka actors using ActorSystem you can visit this blog here. Through this blog, you will get the basics of creating actors.
Now we are going to discuss the question I asked you in the previous paragraph, How do we create subordinate Actors or you can also take subordinates here as children of an Actor. Where Actor acts as a Parent and its subordinate act as a child.
ActorContext
As we discussed in the previous blog, Akka’s ActorSystem creates all top-level actors, which may act as parent or supervisor Actors. So to create a parent or an Actor we execute the ActorSystem.actorOf() function, which creates all top-level Actors.
However, Akka Toolkit has provided an implicit variable, the context of the ActorContext type in the Actor class, as follows:
trait Actor {
implicit val context: ActorContext = {
// Code goes here
}
}
Now as we create the actor by using the function ActorSystem.actorOf() similarly we can create a child of that particular actor using the function “context.actorOf()” and in the actorOf() we need to provide some parameter like this context.actorOf(Props[child_class_name], “child_name“).
Implementation
Let’s build an application in which we are going to create a parent class and a child class and both the classes will extend the Actor and Actor Logging.
object Parent {
case class CreateChild(childName: String)
case class TellChild(message: String)
}
We have provided the object we are going to use in the parent class. Now we are going to have 2 cases one will be for creating a child and the other to talk to the child Reference.
class Parent extends Actor with ActorLogging {
import Parent._
override def receive: Receive = {
case CreateChild(childName) => {
log.info("Creating Child")
}
}
def withChild(childReference: ActorRef): Receive = {
case TellChild(message) => {
}
}
}
As you can see the Parent class has extended the actor to get receive methods and it has imported the parent object and reused it to create two cases. Now we are going to create a child class.
class Child extends Actor with ActorLogging {
override def receive: Receive = {
case message => log.info(s"$self I got [$message]")
}
}
This child class has only one case to log the message that it will receive from its parent class.
Now it’s time to implement the code to create a child of parent class using child class. This is the way to do it.
class Parent extends Actor with ActorLogging {
import Parent._
override def receive: Receive = {
case CreateChild(childName) => {
log.info("Creating Child")
val childRef = context.actorOf(Props[Child], childName)
context.become(withChild(childRef))
}
}
def withChild(childReference: ActorRef): Receive = {
case TellChild(message) => {
childReference ! message
}
}
}
As you can see on line number 8 we have successfully created a child of parent class using child class and we gave it a name. After that, at line number 9 we switch our route to another receive method with name withChild using context.become.
Note: (We will learn about switching routes in coming blogs).
Now case TellChild(message) will print the message from parent to child. The class child will log the received message on the console.
At last, we need to create an actor system and a parent caller. So this is what your application will look like.
Code
import akka.actor.{Actor, ActorLogging, ActorRef, ActorSystem, Props}
import akkaChildActors.childActors.Parent.{CreateChild, TellChild}
object childActors extends App {
object Parent {
case class CreateChild(childName: String)
case class TellChild(message: String)
}
class Parent extends Actor with ActorLogging {
import Parent._
override def receive: Receive = {
case CreateChild(childName) => {
log.info("Creating Child")
val childRef = context.actorOf(Props[Child], childName)
context.become(withChild(childRef))
}
}
def withChild(childReference: ActorRef): Receive = {
case TellChild(message) => {
childReference ! message
}
}
}
class Child extends Actor with ActorLogging {
override def receive: Receive = {
case message => log.info(s"$self I got [$message]")
}
}
val actorSystem = ActorSystem("actorSystem")
val parent = actorSystem.actorOf(Props[Parent], "parent")
parent ! CreateChild("myChild")
parent ! TellChild("Hi new Born Child")
}
The Output
[INFO] [02/10/2022 16:26:19.208] [actorSystem-akka.actor.default-dispatcher-5] [akka://actorSystem/user/parent] Creating Child
[INFO] [02/10/2022 16:26:19.210] [actorSystem-akka.actor.default-dispatcher-7] [akka://actorSystem/user/parent/myChild] Actor[akka://actorSystem/user/parent/myChild#1635667253] I got [Hi new Born Child]
I hope this blog will be useful for you. Thanks for reading will see you in another coming blog.
