Akka消息收件箱以及消息路由、内置状态转换

消息收件箱(Inbox)

Akka框架为我们准备了一个名叫"收件箱"的组件,使用它可以很方便的对Actor进行消息发送和接收,大大方便了应用程序与Actor之间的交互。

public class MyWorker extends UntypedAbstractActor {

    private final LoggingAdapter loggingAdapter= Logging.getLogger(getContext().system(),this);
    public static enum Msg{
        WORKING,DONE,CLOSE;
    }

    @Override
    public void onReceive(Object message) throws Throwable {
        if(message ==Msg.WORKING){
            loggingAdapter.info("I am working");
        }else if (message==Msg.CLOSE){
            loggingAdapter.info("I will shutdown");
            getSender().tell(Msg.CLOSE,getSelf());
            getContext().stop(getSelf());
        }else{
            unhandled(message);
        }
    }

    public static void main(String[] args) {
        ActorSystem system=ActorSystem.create("inboxdemo");
        ActorRef a=system.actorOf(Props.create(MyWorker.class), "worker");

        final Inbox inbox=Inbox.create(system);
        inbox.watch(worker);
        inbox.send(worler, Msg.WORKING);
        inbox.send(worler, Msg.DONE);
        inbox.send(worler, Msg.CLOSE);
        
        while (true){
            Object msg=inbox.receive(Duration.create(1, TimeUnit.SECONDS));
            if(msg==Msg.CLOSE){
                System.out.println("My Worker is Closing");
            }else if(msg instanceof Terminated){
                System.out.println("My worker is dead");
                system.shutdown();
                break;
            }else
                System.out.println(msg);
        }
    }
}

根据ActorSystem构造一个与之绑定的邮箱Inbox。接着使用邮箱监视MyWorker,这样就能在MyWorker停止后得到一个消息通知。向MyWorker发送消息。

消息路由

Akka提供了非常灵活的消息发送机制。有时候,我们也许会使用一组Actor而不是一个Actor来提供一项服务。这一组Actor中所有的Actor都是对等的,也就是说你可以找任何一个Actor来为你服务。这种情况下,如果快速有效地找到合适的Actor呢?为了解决这个问题,Akka使用一个路由器组件来封装消息的调度。系统提供了几种实用的消息路由策略,比如,轮询选择Actor进行消息发送,随机消息发送,将消息发送给最空间的Actor,甚至在组内广播消息。

public class WatchActor extends UntypedAbstractActor {
    private final LoggingAdapter log= Logging.getLogger(getContext().system(),this);
    
    public Router router;//定义路由器组件
    
    {
        List<Routee> routees=new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            ActorRef worker=getContext().actorOf(Props.create(MyWorker.class),"worker_"+i);
            getContext().watch(worker);
            routees.add(new ActorRefRoutee(worker));
        }
        router=new Router(new RoundRobinRoutingLogic(),routees);//指定
    }
    
    
    @Override
    public void onReceive(Object message) throws Throwable {
        if(message instanceof MyWorker.Msg){
            router.route(message,getSender());
        }else if(message instanceof Terminated) {
            router = router.removeRoutee(((Terminated) message).actor());
            System.out.println(((Terminated) message).actor().path() + "is closed,routtes=" + router.routees().size());
            if (router.routees().size() == 0) {
                System.out.println("Close system");
                RouteMain.flag.send(false);
                getContext().system().shutdown;
            }
        }else {
            unhandled(message);
        }
    }
    
	public static Anget<Boolean> flag=Agent.create(true, ExecutionContexts.global());
    public static void main(String[] args) {
        ActorSystem system=ActorSystem.create("route");
        ActorRef a=system.actorOf(Props.create(WatchActor.class),"watcher");
        int i=1;
        while (flag.get()){
            a.tell(MyWorker.Msg.WORKONG,ActorRef.noSender());
            if(i%10==0) a.tell(MyWorker.Msg.CLOSE,ActorRef.noSender());
            i++;
        }
    }
}

内置状态转换

在很多场景下,Actor的业务逻辑可能比较复杂,Actor可能需要根据不同的状态对同一条消息做出不同的处理。一个Actor内部消息处理函数可以拥有多个不同的状态,在特定的状态下,可以对同一消息进行不同的处理,状态之间也可以任意切换。

模拟一个场景:给婴儿Actor发送睡觉和玩两种指令。如果婴儿正在生气,你让他睡觉,他就会说:“我已经生气了”,如果你让他去玩,他就会变得开心。如果他玩的高兴,你让他继续玩,他就会说:“我很愉快”,如果让他睡觉,他会变生气。

public class BabyActor extends UntypedAbstractActor {

    private final LoggingAdapter log= Logging.getLogger(getContext().system(),this);

    public static enum Msg{
        SLEEP,PLAY,CLOSE;
    }
    Procedure<Object> angry=new Procedure<Object>() {
        @Override
        public void apply(Object param) throws Exception {
            System.out.println("angryApply:"+param);
            if(param==Msg.SLEEP){
                getSender().tell("I am already angry",getSelf());
                System.out.println("I am already angry");
            }else if(param ==Msg.PLAY){
                System.out.println("I like play");
                getContext().become( happy);
            }
        }
    };

    Procedure<Object> happy=new Procedure<Object>() {
        @Override
        public void apply(Object param) throws Exception {
            System.out.println("happyApply"+param);
            if(param==Msg.PLAY){
                getSender().tell("I am already happy:",getSender());
                System.out.println("I am already happy");
            }else if(param==Msg.SLEEP){
                System.out.println("I don't want to sleep");
                getContext().become((PartialFunction<Object, BoxedUnit>) angry);
            }
        }
    };

    @Override
    public void onReceive(Object message) throws Throwable {
        System.out.println("OnReceive"+message);
        if(message==Msg.SLEEP){
            getContext().become((PartialFunction<Object, BoxedUnit>) angry);
        }else if(message==Msg.PLAY){
            getContext().become((PartialFunction<Object, BoxedUnit>) happy);
        }else {
            unhandled(message);
        }
    }

    public static void main(String[] args) {
        ActorSystem system=ActorSystem.create("become");
        ActorRef a=system.actorOf(Props.create(BabyActor.class),"babyActor");
        system.actorOf(Props.create(WatchActor.class,a),"wathcer");
        a.tell(Msg.PLAY,ActorRef.noSender());
        a.tell(Msg.SLEEP,ActorRef.noSender());
        a.tell(Msg.PLAY,ActorRef.noSender());
        a.tell(Msg.PLAY,ActorRef.noSender());

        a.tell(PoisonPill.getInstance(),ActorRef.noSender());
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值