Before describing how to create an actor, let's look at a class props. Props is a configuration class that specifies the parameters for creating actors, and so on. The following are some typical applications of Props, Props
1) directly into the class of the actor you need to create
Import Akka.actor.ActorRef;
Import Akka.actor.ActorSystem;
Import Akka.actor.Props;
Import Akka.actor.UntypedActor; public class Createtest {enum MSG {HI, OK} static class Actor1 extends Untypedactor {@Override public void OnReceive (Object message) throws Exception {//TODO auto-generated Method stub if (message instanceof MSG) {if (Message.equals (MSG).
OK)) {System.out.println ("I receive OK");
} else {unhandled (message);
}} else {unhandled (message); }}}} Static class Actor2 extends Untypedactor {@Override public void OnReceive (Object message) throws Except
Ion {if (message instanceof MSG) {if (Message.equals (Msg.hi)) {System.out.println ("I receive HI"); Getsender (). Tell (MSG.
OK, Getself ());
} else {unhandled (message);
}} else {unhandled (message); }}} public static void communication () {//Here directly pass in the class Props Props1 = Props.create (Actor1.class) of the actor you need to create
;Props props2 = props.create (Actor2.class);
Create actor Final Actorsystem system = actorsystem.create ("Mysystem") using props;
Final Actorref Actor1 = system.actorof (Props1, "Actor1");
Final Actorref Actor2 = system.actorof (PROPS2, "Actor2");
Actor2.tell (Msg.hi, Actor1);
System.stop (Actor1);
System.stop (ACTOR2);
System.shutdown ();
} public static void Main (string[] args) {communication (); }
}
In this case, the default constructor is called when the actor is created.
2) directly to the class of the actor you want to create, and the parameters of the constructor
Import Akka.actor.ActorRef;
Import Akka.actor.ActorSystem;
Import Akka.actor.Props;
Import Akka.actor.UntypedActor;
public class Createtest {enum MSG {HI, OK} static class Actor1 extends Untypedactor {String name;
int index;
Actor1 (String name, int index) {this.name = name;
This.index = index; } @Override public void OnReceive (Object message) throws Exception {System.out.println (name + "_" + Index + "R
Eceive message "); if (Message instanceof msg) {if (Message.equals (msg).
OK)) {System.out.println ("I receive OK");
} else {unhandled (message);
}} else {unhandled (message);
}}} static class Actor2 extends Untypedactor {String name;
int index;
Actor2 (String name, int index) {this.name = name;
This.index = index; } @Override public void OnReceive (Object message) throws Exception {System.out.println (name + "_" + Index + "R
Eceive message "); if (message instanceof MSG) {if (Message.equals (Msg.hi))
{SYSTEM.OUT.PRINTLN ("I receive hi"); Getsender (). Tell (MSG.
OK, Getself ());
} else {unhandled (message);
}} else {unhandled (message);
}}} public static void communication () {//here directly into the class of the actor you need to create, and pass in the construction parameters required to create the actor.
Props Props1 = props.create (Actor1.class, "Actor1", 1);
Props props2 = props.create (Actor2.class, "Actor2", 1);
Create actor Final Actorsystem system = actorsystem.create ("Mysystem") using props;
Final Actorref Actor1 = system.actorof (Props1, "Actor1");
Final Actorref Actor2 = system.actorof (PROPS2, "Actor2");
Actor2.tell (Msg.hi, Actor1);
System.stop (Actor1);
System.stop (ACTOR2);
System.shutdown ();
} public static void Main (string[] args) {communication ();
}
}
The props1 created above, the parameters passed are Actor1.class, "Actor1", 1. where "Actor1" and 1 correspond to two parameters of a constructor. Back to Actor1, which defines two display constructors, the arguments passed are name (String) and index (int), so the above-mentioned "Actor1" and 1 exactly match the two parameters that were successful. Props2.
Running the above program can be seen,
Actor2_1 Receive Message
I receive Hi
actor1_1 Receive Message
I receive OK
[INFO] [07/12/2014 11:24:16.189] [mysystem-akka.actor.default-dispatcher-3] [Akka://mysystem/user] Message [Akka.actor.StopChild] From Actor[akka://mysystem/deadletters] to Actor[akka://mysystem/user] is not delivered. [1] dead letters encountered. This logging can is turned off or adjusted with configuration settings ' akka.log-dead-letters ' and ' akka.log-dead-letters- During-shutdown '.
[INFO] [07/12/2014 11:24:16.189] [Mysystem-akka.actor.default-dispatcher-3] [Akka://mysystem/user] Message [Akka.actor.StopChild] from actor[akka:// Mysystem/deadletters] to Actor[akka://mysystem/user] is not delivered. [2] dead letters encountered. This logging can is turned off or adjusted with configuration settings ' akka.log-dead-letters ' and ' akka.log-dead-letters- During-shutdown '.
So what happens if the arguments passed in cannot match the parameters of the constructor.
Modify the PROPS1 creation statement as follows,
Props Props1 = props.create (Actor1.class, "Actor1", 1, 2);
This situation does not match any of the constructors, and the following information appears after running
Exception in thread "main" java.lang.IllegalArgumentException:no matching constructor found on class Createtest$actor1 fo R arguments [Class Java.lang.String, Class Java.lang.Integer, class Java.lang.Integer] at
akka.util.reflect$.error $ (reflect.scala:82) at
akka.util.reflect$.findconstructor (reflect.scala:106)
at Akka.actor.argsreflectconstructor.<init> (props.scala:350) at
akka.actor.indirectactorproducer$.apply ( props.scala:309) at
akka.actor.Props.producer (props.scala:176) at
akka.actor.props.<init> ( props.scala:189) at
akka.actor.props$.create (props.scala:99) at
akka.actor.props$.create (Props.scala:99) At
akka.actor.Props.create (Props.scala) at
createtest.communication (createtest.java:66)
at Createtest.main (createtest.java:81)
It is obvious that in this case a generic IllegalArgumentException exception is thrown, and the subsequent error message is explicitly prompted.
3) An instance of the incoming Creator<t> interface
Import Java.util.concurrent.atomic.AtomicInteger;
Import Akka.actor.ActorRef;
Import Akka.actor.ActorSystem;
Import Akka.actor.Props;
Import Akka.actor.UntypedActor;
Import Akka.japi.Creator;
public class Createtest {enum MSG {HI, OK} static class Creator1 implements creator<actor1>{//Multithreading Guarantee
Atomicinteger index = new Atomicinteger ();
/** * */private static final long serialversionuid = 1L; Public Actor1 Create () throws Exception {//TODO auto-generated method stub return new Actor1 ("Actor1", Index.getan
Dadd (1));
}} Static Class Creator2 implements creator<actor2>{//Multithreading guarantee Atomicinteger index = new Atomicinteger ();
/** * */private static final long serialversionuid = 1L; Public Actor2 Create () throws Exception {//TODO auto-generated method stub return new Actor2 ("Actor2", Index.getan
Dadd (1));
}} static Class Actor1 extends Untypedactor {String name;
int index; Actor1 (String name,int index) {this.name = name;
This.index = index; } @Override public void OnReceive (Object message) throws Exception {System.out.println (name + "_" + Index + "R
Eceive message "); if (Message instanceof msg) {if (Message.equals (msg).
OK)) {System.out.println ("I receive OK");
} else {unhandled (message);
}} else {unhandled (message);
}}} static class Actor2 extends Untypedactor {String name;
int index;
Actor2 (String name, int index) {this.name = name;
This.index = index; } @Override public void OnReceive (Object message) throws Exception {System.out.println (name + "_" + Index + "R
Eceive message ");
if (message instanceof MSG) {if (Message.equals (Msg.hi)) {System.out.println ("I receive HI"); Getsender (). Tell (MSG.
OK, Getself ());
} else {unhandled (message);
}} else {unhandled (message); }}} public static void communication () {///Create creator instance, thisCreator is used to create the actor and then creator into props Creator1 Creator1 = new Creator1 ();
Creator2 Creator2 = new Creator2 ();
Props Props1 = props.create (Creator1);
Props props2 = props.create (Creator2);
Create actor Final Actorsystem system = actorsystem.create ("Mysystem") using props;
Final Actorref Actor1 = system.actorof (PROPS1);
Final Actorref Actor2 = system.actorof (PROPS2);
Actor2.tell (Msg.hi, Actor1);
System.stop (Actor1);
System.stop (ACTOR2);
System.shutdown ();
} public static void Main (string[] args) {communication ();
}
}
Here Creator1 and Creator2 are very much like a factory, and its create method is used for creating actors. It is important to note that the Creator class must be static. validation is performed when the props is created. Creator<t> is a template class that specifies T when implementing this interface, which determines the type of actor that this Creator will create in the future.
What happens if the creator is not static.
Modify the above code to define the Creator1 as follows,
public class Creator1 implements creator<actor1>{
Then modify the Creator1 's creation code as follows,
Createtest creatertest = new Createtest ();
Creator1 Creator1 = Creatertest.new Creator1 ();
The following results appear after running the code,
Exception in thread "main" Java.lang.IllegalArgumentException:cannot use non-static local Creator to create actors; Make it static (e.g. local to a static method) or top-level at
akka.actor.props$.create (props.scala:112) at
akka.a ctor. Props.create (Props.scala) at
createtest.communication (createtest.java:102) at
Createtest.main ( createtest.java:117)
You cannot create a actors using a non-static local creator.
Props Best PracticesAs mentioned in the Akka documentation: defining a static method in the actor class for acquiring props is a good way to make the definition of props as close as possible to the definition of the actor. According to the example on the official website, we have modified the Actor2 in the example above (extracted as a class separately)
Import Java.util.concurrent.atomic.AtomicInteger;
Import Akka.actor.Props;
Import Akka.actor.UntypedActor;
Import Akka.japi.Creator;
public class Actor2 extends Untypedactor {String name;
int index;
Public Actor2 (String name, int index) {this.name = name;
This.index = index; } @Override public void OnReceive (Object message) throws Exception {System.out.println (name + "_" + Index + "Receiv
E-Message ");
if (message instanceof MSG) {if (Message.equals (Msg.hi)) {System.out.println ("I receive HI"); Getsender (). Tell (MSG.
OK, Getself ());
} else {unhandled (message);
}} else {unhandled (message); }} public static Props Props () {return props.create (new creator<actor2> () {/** * */private
Static final Long serialversionuid = 1L;
Private Atomicinteger index = new Atomicinteger (); Public Actor2 Create () throws Exception {//TODO auto-generated method stub return new Actor2 ("Actor2", Index.get Andadd (1));
}
}); }
}
Here, an instance of the incoming anonymous class is used in the Create method. The error that occurs after running is the same as mentioned above, it is prompt creator must be static class. Take a look at Props's realization, Https://github.com/akka/akka/blob/master/akka-actor/src/main/scala/akka/actor/Props.scala. Although there is no system to learn Scala, the first check in the Create method is very clear that creator must be a static class,
def create[t <: Actor] (creator:creator[t]): Props = {val cc = Creator.getclass if ((Cc.getenclosingclass ne n ull) && (cc.getmodifiers & modifier.static) = = 0) throw new IllegalArgumentException ("Cannot use Non-sta Tic local Creator to create actors; Make it static (e.g. local to a static method) or top-level ") val ac = classof[actor] val coc = classof[creator[_] ] Val actorclass = Reflect.findmarker (cc, COC) match {case T:parameterizedtype⇒t.getactualtypeargume Nts.head Match {case c:class[_]⇒c//since T <: Actor case V:TYPEVARIABLE[_]⇒V.G Etbounds Collectfirst {case C:class[_] if Ac.isassignablefrom (c) && c! = ac⇒c} getorelse ac case x ⇒throw New IllegalArgumentException (S "Unsupported type found in Creator argument [$x]")} Case C:class[_] if (c = = COC) ⇒throw new IllegalArgumentException (S "Erased Creator types is unsupported, use PROPS.CReate (Actorclass, creator) instead ")} apply (Defaultdeploy, Classof[creatorconsumer], Actorclass:: Creator:: Nil )
}
It is unclear why this is done. I guess it's because of the features of the Scala language that although we can use Akka based on Java, the underlying Akka package is still written by Scala, so it has some requirements for parameters. Since the above method is not good, then how to do it. Use Eclipse shortcut key ctrl+1 on anonymous classes,
After selecting the second one, the code is refactored to,
Import Java.util.concurrent.atomic.AtomicInteger;
Import Akka.actor.Props;
Import Akka.actor.UntypedActor;
Import Akka.japi.Creator; public class Actor2 extends Untypedactor {private static final class Creatorimplementation implements creator<actor2& Gt
{/** * */private static final long serialversionuid = 1L;
Private Atomicinteger index = new Atomicinteger (); Public Actor2 Create () throws Exception {//TODO auto-generated method stub return new Actor2 ("Actor2", Index.getan
Dadd (1));
}}, String name;
int index;
Public Actor2 (String name, int index) {this.name = name;
This.index = index; } @Override public void OnReceive (Object message) throws Exception {System.out.println (name + "_" + Index + "Receiv
E-Message ");
if (message instanceof MSG) {if (Message.equals (Msg.hi)) {System.out.println ("I receive HI"); Getsender (). Tell (MSG.
OK, Getself ());
} else {unhandled (message);
}} else {unhandled (message); }
} public static Props Props () {return props.create (new Creatorimplementation ()); }
}
The original anonymous class is shown to be extracted for a static inner class, which is actually similar to the method we started with.
The Actor1 is then refactored in the same way, modifying the test class as shown below,
Import Akka.actor.ActorRef;
Import Akka.actor.ActorSystem;
public class Createtest {public
void communication () {
//use props to create actor
final Actorsystem system = Actorsys Tem.create ("Mysystem");
Final Actorref Actor1 = System.actorof (Actor1.props ());
Final Actorref Actor2 = System.actorof (Actor2.props ());
Actor2.tell (Msg.hi, actor1);
System.stop (Actor1);
System.stop (ACTOR2);
System.shutdown ();
}
public static void Main (string[] args) {
new Createtest (). Communication ();
}
}
Everything is fine after running.
ACTOR2_0 Receive Message
I receive Hi
actor1_0 Receive Message
I receive OK
[INFO] [07/13/2014 01:27:22.357] [mysystem-akka.actor.default-dispatcher-5] [akka://mysystem/user/$a] Message [ Akka.dispatch.sysmsg.Terminate] from actor[akka://mysystem/user/$a #1651324613) to actor[akka://mysystem/user/$a # 1651324613] was not delivered. [1] dead letters encountered. This logging can is turned off or adjusted with configuration settings ' akka.log-dead-letters ' and ' akka.log-dead-letters- During-shutdown '.
[INFO] [07/13/2014 01:27:22.359] [Mysystem-akka.actor.default-dispatcher-5] [Akka://mysystem/user] Message [Akka.actor.StopChild] from actor[akka:// Mysystem/deadletters] to Actor[akka://mysystem/user] is not delivered. [2] dead letters encountered. This logging can is turned off or adjusted with configuration settings ' akka.log-dead-letters ' and ' akka.log-dead-letters- During-shutdown '.
different actor Types
Top actor
The previous example creates an actor that is called the Systemactor,
actors created using this method belong to the top actors, which are supervised directly by the Guardian actor provided by the system.
Modify the test class, add the following statement,
System.out.println (System.guardian (). path ());
System.out.println (Actor1.path ());
System.out.println (Actor2.path ());
After running, get the following information,
akka://mysystem/user actor2_0 receive message akka://mysystem/user/$a I receive Hi akka://mysystem/ user/$b ACTOR1_0 Receive message I receive OK [INFO] [07/13/2014 11:43:02.350] [mysystem-akka.actor.default-dispatcher-2 ] [akka://mysystem/user/$a] Message [akka.dispatch.sysmsg.Terminate] from actor[akka://mysystem/user/$a #1387654750] To actor[akka://mysystem/user/$a #1387654750] is not delivered. [1] dead letters encountered. This logging can is turned off or adjusted with configuration settings ' akka.log-dead-letters ' and ' akka.log-dead-letters-
During-shutdown '. [INFO] [07/13/2014 11:43:02.352] [Mysystem-akka.actor.default-dispatcher-2] [Akka://mysystem/user] Message [Akka.actor.StopChild] from actor[akka:// Mysystem/deadletters] to Actor[akka://mysystem/user] is not delivered. [2] dead letters encountered. This logging can is turned off or adjusted with configuration settings ' akka.log-dead-letters ' and ' akka.log-dead-letters-
During-shutdown '.
Compared to the previous results, a few more paths, the structure of the path is akka://xxx/xxx/.... You can see that Mysystem is the name of the systemactor that we set, and the user is the Guardian actor's path, and the Guardian actor is primarily responsible for the supervision of the top actor, as mentioned earlier. Because we did not set the path of Actor1 and Actor2, the system generated the default path of $ A and $b for these two actors. If the path set for Actor1 is "Actor1", then Actor1 's path is Akka://mysystem/user/actor1,actor2.
Other actorsUse the context of an actor to create a child actor for this actor.
Modify the Actor1, override the Prestart method,
@Override public
void Prestart () throws Exception {
final actorref Actor2 = GetContext (). Actorof (Actor2.props () , "Actor2");
Actor2.tell (Msg.hi, getself ());
System.out.println (Getself (). Path (). parent ());
System.out.println (Getself (). path ());
System.out.println (Actor2.path ());
}
Modify the test class as follows,
Import Akka.actor.ActorRef;
Import Akka.actor.ActorSystem;
public class Createtest {public
void communication () {
//use props to create actor
final Actorsystem system = Actorsys Tem.create ("Mysystem");
Final Actorref Actor1 = System.actorof (Actor1.props (), "Actor1");
System.shutdown ();
}
public static void Main (string[] args) {
new Createtest (). Communication ();
}
}
After running, get the following information,
ACTOR2_0 Receive Message
I receive Hi
akka://mysystem/user
akka://mysystem/user/actor1
akka:// Mysystem/user/actor1/actor2
ACTOR1_0 Receive Message
I receive OK
Can be launched,
guardian___ |___actor1___ |___ |___actor2
in the Akk documentation, it is advisable to create a tree-like structure that creates an appropriate number of sub-actors for each actor so that it adapts to the application's fault tolerant architecture.
(it's recommended to create a hierarchy of children, grand-children and so on such that it fits the logical Failureha Ndling structure of the application, see Actor Systems)
ActorrefThe return value type, such as whether to create a top-level actor or a non-top actor,actorof, is actorref. Actorref holds an instance of the actor and is the only one that can interact with the actor. The actorref is constant and corresponds to the actor one by one it represents. The Actorref is also serializable, which means that you can serialize the actorref and transmit it over the network to the remote node, which is deserialized on the remote host and still represents the same actor on the original node.