Actor construction

Actor construction is a common source of difficulty for people new to Akka. Unlike (most) ordinary objects, you never instantiate actors explicitly. You would never write, for instance, val echo = new EchoActor. In fact, if you try this, Akka raises an exception.

Creating actors in Akka is a two-step process: you first create a Props object, which encapsulates the properties needed to construct an actor. The way to construct a Props object differs depending on whether the actor takes constructor arguments. If the constructor takes no arguments, we simply pass the actor class as a type parameter to Props:

val echoProps = Props[EchoActor]

If we have an actor whose constructor does take arguments, we must pass these as additional arguments when defining the Props object. Let's consider the following actor, for instance:

class TestActor(a:String, b:Int) extends Actor { ... }

We pass the constructor arguments to the Props object as follows:

val testProps = Props(classOf[TestActor], "hello", 2)

The Props instance just embodies the configuration for creating an actor. It does not actually create anything. To create an actor, we pass the Props instance to the system.actorOf method, defined on the ActorSystem instance:

val system = ActorSystem("HelloActors")
val echo1 = system.actorOf(echoProps, name="hello-1")

The name parameter is optional but is useful for logging and error messages. The value returned by .actorOf is not the actor itself: it is a reference to the actor (it helps to think of it as an address that the actor lives at) and has the ActorRef type. ActorRef is immutable, but it can be serialized and duplicated without affecting the underlying actor.

There is another way to create actors besides calling actorOf on the actor system: each actor exposes a context.actorOf method that takes a Props instance as its argument. The context is only accessible from within the actor:

class TestParentActor extends Actor {
  val echoChild = context.actorOf(echoProps, name="hello-child")
  ...
}

The difference between an actor created from the actor system and an actor created from another actor's context lies in the actor hierarchy: each actor has a parent. Any actor created within another actor's context will have that actor as its parent. An actor created by the actor system has a predefined actor, called the user guardian, as its parent. We will understand the importance of the actor hierarchy when we study the actor lifecycle at the end of this chapter.

A very common idiom is to define a props method in an actor's companion object that acts as a factory method for Props instances for that actor. Let's amend the EchoActor companion object:

object EchoActor {
  def props:Props = Props[EchoActor]
  
  // message case class definitions here
}

We can then instantiate the actor as follows:

val echoActor = system.actorOf(EchoActor.props)
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset