Classic Actor | Become/Unbecome

AKKa支持在runtime时hotswapped (热插拔)Actor的message loop:在Actor中调用context.become方法。hotswapped的代码被存在一个栈中,可以被pushed(replacing 或 adding 在顶部)和popped。become一个特别好的例子是用它来实现一个有限状态机(FSM)。 Become/Unbecome特性很方便去实现有限状态转换机。

需要注意的是,当actor被它的Supervisor重新启动时,它将重置为原始行为。[1]

import akka.actor.AbstractActor;
import akka.actor.Props;
import akka.event.Logging;
import akka.event.LoggingAdapter;
public class RequestActor6 extends AbstractActor {
    protected final String name;
    protected final LoggingAdapter log = Logging.getLogger(context().system(), this);
    private Receive hiHandler;
    private Receive helloHandler;
    public RequestActor6(String name) {
        this.name = name;
        hiHandler = receiveBuilder().matchEquals("Hi", message - >{
            log.info(message);
            getContext().become(helloHandler);
        }).matchAny(message - >{
            log.error(message.toString());
        }).build();
        helloHandler = receiveBuilder().matchEquals("Hello", message - >{
            log.info(message);
            getContext().become(hiHandler);
        }).matchAny(message - >{
            log.error(message.toString());
        }).build();
    }
    public static Props props(String name) {
        return Props.create(RequestActor6.class, name);
    }
    @Override public Receive createReceive() {
        return receiveBuilder().match(String.class, message - >{
            log.info(message);
            getContext().become(helloHandler);
        }).build();
    }
}
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.testkit.TestActorRef;
import org.junit.jupiter.api.Test;
class RequestActor6Test {
    ActorSystem system = ActorSystem.create();
    @Test public void test() {
        TestActorRef < RequestActor6 > ref = TestActorRef.create(system, RequestActor6.props("request6"));
        ref.tell("init", ActorRef.noSender()); //info init
        ref.tell("Hello", ActorRef.noSender()); //info Hello
        ref.tell("Hi", ActorRef.noSender()); //info Hi
        ref.tell("Hello", ActorRef.noSender()); //info Hello
        ref.tell("Hi", ActorRef.noSender()); //info Hi
        ref.tell("Hello", ActorRef.noSender()); //info Hello
        ref.tell("Hello", ActorRef.noSender()); //error Hello
    }
}

上面例子展示的是通过replace策略来替换栈头的handle,除此外还能通过pop(即 unbecom)策略移除当前handle切换上一个handle,在pop策略下需要保证"push"和“pop”操作次数要相等,否则会引起内存泄漏。

import akka.actor.AbstractActor;
import akka.actor.Props;
import akka.event.Logging;
import akka.event.LoggingAdapter;
public class RequestActorUnbecome extends AbstractActor {
    protected final String name;
    protected final LoggingAdapter log = Logging.getLogger(context().system(), this);
    private AbstractActor.Receive hiHandler;
    private AbstractActor.Receive helloHandler;
    public RequestActorUnbecome(String name) {
        this.name = name;
        hiHandler = receiveBuilder().matchEquals("Hi", message - >{
            log.info(message);
            getContext().unbecome(); //切换到上一个handle
        }).matchAny(message - >{
            log.error(message.toString());
        }).build();
        helloHandler = receiveBuilder().matchEquals("Hello", message - >{
            log.info(message);
            getContext().become(hiHandler, false);//采用“pop”策略
        }).matchAny(message - >{
            log.error(message.toString());
        }).build();
    }
    static Props props(String name) {
        return Props.create(RequestActorUnbecome.class, name);
    }
    @Override public Receive createReceive() {
        return receiveBuilder().matchEquals("init", message - >{
            log.info(message);
            getContext().become(helloHandler);
        }).build();
    }
}
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.testkit.TestActorRef;
import org.junit.jupiter.api.Test;
class RequestActorUnbecomeTest {
    ActorSystem system = ActorSystem.create();
    @Test
    public void test() {
        TestActorRef<RequestActorUnbecome> actorRef = TestActorRef.create(system,RequestActorUnbecome.props("Request"));
        actorRef.tell("init", ActorRef.noSender());// info init
        actorRef.tell("Hello",ActorRef.noSender());//info Hello
        actorRef.tell("Hi",ActorRef.noSender());//info Hi
        actorRef.tell("Hello",ActorRef.noSender());//info Hello
        actorRef.tell("Hello",ActorRef.noSender());//error Hello
        actorRef.tell("Hi",ActorRef.noSender());//info Hi
    }
posted @ 2020-11-16 00:00  听说这是最长的名字了  阅读(194)  评论(0编辑  收藏  举报