actor锚定模式是指使用actorSelection对acor进行锚定的设计模式,也可以说是一个对actor的引用技巧。在某些情况下,我们可能需要能够根据Actor的path锚定对应的实例。简单来说就是,无论actor是因为异常导致的restart还是用户主动stop,然后再重新actorOf,只要actor的路径和name相同,我们都希望把消息发送给改Actor的一个实例。那我们来看一下actorSelection和ActorRef的使用区别。
class AnchorActor extends Actor{ override def preStart(): Unit = { super.preStart() println(s"self=$self,path=${self.path}") } override def receive: Receive = { case any => println(s"Hello $any") } } object AnchorPattern{ def main(args: Array[String]): Unit = { val system = ActorSystem("AnchorPattern",ConfigFactory.load()) val anchorActor = system.actorOf(Props(new AnchorActor),"anchorActor") anchorActor ! 1 val anchorActorSelection = system.actorSelection("/user/anchorActor") anchorActorSelection ! 2 system.stop(anchorActor) // 等待anchorActor彻底stop Thread.sleep(3*1000) system.actorOf(Props(new AnchorActor),"anchorActor") anchorActor ! 3 anchorActorSelection ! 4 } }
输出:
self=Actor[akka://AnchorPattern/user/anchorActor#-1941442858],path=akka://AnchorPattern/user/anchorActor Hello 1 Hello 2 self=Actor[akka://AnchorPattern/user/anchorActor#489200584],path=akka://AnchorPattern/user/anchorActor Hello 4 [INFO] [07/31/2018 16:59:48.102] [AnchorPattern-akka.actor.default-dispatcher-5] [akka://AnchorPattern/user/anchorActor] Message [java.lang.Integer] without sender to Actor[akka://AnchorPattern/user/anchorActor#-1941442858] was not delivered. [1] dead letters encountered. If this is not an expected behavior, then [Actor[akka://AnchorPattern/user/anchorActor#-1941442858]] may have terminated unexpectedly, This logging can be turned off or adjusted with configuration settings ‘akka.log-dead-letters‘ and ‘akka.log-dead-letters-during-shutdown‘.
上面代码中,我们创建了一个AnchorActor实例,然后通过ActorRef和ActorSelection分别给AnchorActor发送了两条消息,anchorActor都收到了。之后我们把之前的AnchorActor实例给stop掉,再ActorRef和ActorSelection分别发送消息,由输出我们可以看出,第二次发消息时,只有anchorActorSelection发送成功了。这就证明了,ActorRef只能指向Actor的某个特定实例;而ActorSelection通过路径指向Actor的所有实例,即使该actor的实例被销毁然后重新创建,ActorSelection也能指向新的实例。
我这篇博客把ActorSelection发消息成为actor锚定模式,主要是想告诉读者ActorSelection与ActorRef的区别。那读者可能会问,既然ActorSelection可以对actor进行锚定,能指向最新的实例,为什么还要有ActorRef存在的必要呢?其实这要区别对待,结合场景来谈具体使用哪种形式。如果你的业务场景下,不区分Actor的实例,只要路径和name相同,就把所有的消息发送给它,那就是用ActorSelection;如果你的场景需要严格区分Actor的实例,比如不同的实例就代表不同的服务对象,不同服务对象的结果是不同的,此时就需要用ActorRef来通信。
虽然这个设计模式比较简单,但希望读者能够严格区分二者的关系,在合适的场景使用合适的技术。
原文地址:https://www.cnblogs.com/gabry/p/9397078.html