akka学习教程(四) actor生命周期

akka系列文章目录

这里写图片描述

import akka.actor.UntypedActor;
import akka.event.Logging;
import akka.event.LoggingAdapter;

public class MyWork extends UntypedActor {

    LoggingAdapter logger = Logging.getLogger(getContext().system(), this);

    public static enum Msg{
        WORKING, DONE, CLOSE;
    }

    /**
    * 
    * /
    @Override
    public void preStart() {
        logger.info("myWork starting.");
    }

    @Override
    public void postStop() throws Exception {
        logger.info("myWork stoping..");
    }

    @Override
    public void onReceive(Object msg) {
        try {
            if(msg == Msg.WORKING){
                logger.info("i am  working");
            }else if(msg == Msg.DONE){
                logger.info("stop  working");
            }else if(msg == Msg.CLOSE){
                logger.info("stop  close");
                getSender().tell(Msg.CLOSE, getSelf());
                getContext().stop(getSelf());
            }else {
                unhandled(msg);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
import akka.actor.ActorRef;
import akka.actor.Terminated;
import akka.actor.UntypedActor;
import akka.event.Logging;
import akka.event.LoggingAdapter;

public class WatchActor extends UntypedActor {

  LoggingAdapter logger = Logging.getLogger(getContext().system(), this);

  /**
   * 监听一个actor
   * @param actorRef
   */
  public WatchActor(ActorRef actorRef){
    getContext().watch(actorRef);
  }

  @Override
  public void onReceive(Object msg) throws InterruptedException {
    if(msg instanceof Terminated){
      //这里简单打印一下,然后停止system
      logger.error(((Terminated)msg).getActor().path() + " has Terminated. now shutdown the system");
      getContext().system().shutdown();
    }else{
      unhandled(msg);
    }

  }

}

import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.PoisonPill;
import akka.actor.Props;
import com.typesafe.config.ConfigFactory;

public class Main {

  public static void main(String[] args) {
    //创建ActorSystem。一般来说,一个系统只需要一个ActorSystem。
    //参数1:系统名称。参数2:配置文件
    ActorSystem system = ActorSystem.create("Hello", ConfigFactory.load("akka.config"));
    ActorRef myWork = system.actorOf(Props.create(MyWork.class), "MyWork");
    ActorRef watchActor = system.actorOf(Props.create(WatchActor.class, myWork), "WatchActor");

    myWork.tell(MyWork.Msg.WORKING, ActorRef.noSender());
    myWork.tell(MyWork.Msg.DONE, ActorRef.noSender());

    //中断myWork
    myWork.tell(PoisonPill.getInstance(), ActorRef.noSender());
  }
}

输出结果:

[INFO] [01/05/2017 15:26:15.705] [Hello-akka.actor.default-dispatcher-4] [akka://Hello/user/MyWork] myWork starting.
[INFO] [01/05/2017 15:26:15.730] [Hello-akka.actor.default-dispatcher-4] [akka://Hello/user/MyWork] i am  working
[INFO] [01/05/2017 15:26:15.730] [Hello-akka.actor.default-dispatcher-4] [akka://Hello/user/MyWork] stop  working
[INFO] [01/05/2017 15:26:15.736] [Hello-akka.actor.default-dispatcher-4] [akka://Hello/user/MyWork] myWork stoping..
[ERROR] [01/05/2017 15:26:15.749] [Hello-akka.actor.default-dispatcher-10] [akka://Hello/user/WatchActor] akka://Hello/user/MyWork has Terminated. now shutdown the system

监督

这里可以对actor进行监督,在actor报出异常的时候进行处理。由于这个和生命周期也有关,所以放到这里一起说了。

akka监督策略有两种:

  • OneForOneStrategy
    • 只对出问题的子actor进行处理. 这是默认策略
  • AllForOneStrategy
    • 对子actor以及他的所有兄弟actor进行处理

定义监督者的行为:


package akka.strategy;

import akka.actor.OneForOneStrategy;
import akka.actor.Props;
import akka.actor.SupervisorStrategy;
import akka.actor.UntypedActor;
import akka.japi.Function;
import scala.concurrent.duration.Duration;

import java.util.concurrent.TimeUnit;

/**
 * Created by liubenlong on 2017/1/9.
 * 监督者,监督策略
 */
public class SuperVisor extends UntypedActor{

    /**
     * 配置自己的strategy
     * @return
     */
    @Override
    public SupervisorStrategy supervisorStrategy(){
        return new OneForOneStrategy(3, Duration.create(1, TimeUnit.MINUTES),//一分钟内重试3次,超过则kill掉actor
                new Function<Throwable, SupervisorStrategy.Directive>() {
                    @Override
                    public SupervisorStrategy.Directive apply(Throwable throwable) throws Exception {
                        if(throwable instanceof ArithmeticException){//ArithmeticException是出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时,抛出此类的一个实例。
                            System.out.println("meet ArithmeticException ,just resume.");
                            return  SupervisorStrategy.resume();//继续; 重新开始; 恢复职位;
                        }else if(throwable instanceof NullPointerException){
                            System.out.println("meet NullPointerException , restart.");
                            return SupervisorStrategy.restart();
                        }else if(throwable instanceof IllegalArgumentException){
                            System.out.println("meet IllegalArgumentException ,stop.");
                            return SupervisorStrategy.stop();
                        }else{
                            System.out.println("escalate.");
                            return SupervisorStrategy.escalate();//使逐步升级; 使逐步上升; 乘自动梯上升;也就是交给更上层的actor处理。抛出异常
                        }
                    }
                });
    }

    @Override
    public void onReceive(Object o) throws Throwable {
        if(o instanceof Props){
            getContext().actorOf((Props)o , "restartActor");
        }else{
            unhandled(o);
        }
    }
}

定义restartActor的实现:

package akka.strategy;

import akka.actor.UntypedActor;
import scala.Option;

/**
 * Created by liubenlong on 2017/1/12.
 */
public class RestartActor extends UntypedActor {

    public  enum  Msg{
        DONE, RESTART;
    }


    @Override
    public void preStart() throws Exception {
        System.out.println("preStart    hashCode=" + this.hashCode());
    }
    @Override
    public void postStop() throws Exception {
        System.out.println("postStop    hashCode=" + this.hashCode());
    }



    @Override
    public void preRestart(Throwable reason, Option<Object> message) throws Exception {
        System.out.println("preRestart    hashCode=" + this.hashCode());
    }
    @Override
    public void postRestart(Throwable reason) throws Exception {
        super.postRestart(reason);
        System.out.println("postRestart    hashCode=" + this.hashCode());
    }



    @Override
    public void onReceive(Object o) throws Throwable {
        if(o == Msg.DONE){
            getContext().stop(getSelf());
        }else if(o == Msg.RESTART){
            System.out.println(((Object) null).toString());
            //抛出异常,默认会被restart,但这里会resume
            //double a = 1/0;
        }else{
            unhandled(o);
        }

    }
}

定义main方法:

package akka.strategy;

import akka.actor.*;
import com.typesafe.config.ConfigFactory;

/**
 * Created by liubenlong on 2017/1/12.
 */
public class Main {

    public static void main(String[] args) {
        ActorSystem system = ActorSystem.create("strategy", ConfigFactory.load("akka.config"));
        ActorRef superVisor = system.actorOf(Props.create(SuperVisor.class), "SuperVisor");
        superVisor.tell(Props.create(RestartActor.class), ActorRef.noSender());

        ActorSelection actorSelection = system.actorSelection("akka://strategy/user/SuperVisor/restartActor");//这是akka的路径。restartActor是在SuperVisor中创建的。

        for(int i = 0 ; i < 100 ; i ++){
            actorSelection.tell(RestartActor.Msg.RESTART, ActorRef.noSender());
        }
    }

}

输出结果(省略部分异常):

com.intellij.rt.execution.application.AppMain akka.strategy.Main
preStart    hashCode=463293128
meet NullPointerException , restart.
preRestart    hashCode=463293128
preStart    hashCode=1195770342
postRestart    hashCode=1195770342
meet NullPointerException , restart.
preRestart    hashCode=1195770342
preStart    hashCode=1139511720
postRestart    hashCode=1139511720
meet NullPointerException , restart.
preRestart    hashCode=1139511720
preStart    hashCode=1906622979
postRestart    hashCode=1906622979
meet NullPointerException , restart.
postStop    hashCode=1906622979
[ERROR] [01/12/2017 10:52:05.563] [strategy-akka.actor.default-dispatcher-2] [akka://strategy/user/SuperVisor/restartActor] null
java.lang.NullPointerException
    at akka.strategy.RestartActor.onReceive(RestartActor.java:44)
    at akka.actor.UntypedActor$$anonfun$receive$1.applyOrElse(UntypedActor.scala:165)

结果分析:
preStart是restartActor初始化时调用的,他的hashcode是463293128,接着遇到空指针异常,根据自定义策略,会重启改actor。此时会调用preRestart,注意他的hashcode依然是463293128,因为preRestart是在正式启动前在老的actor上调用的。
随后打印出preStart,说明新的actor开始创建了,他的hashcode是1195770342,新的actor实例将替代旧的实例工作,这说明同一个restartActor工作的过程中,未必真的是同一个actor。重启完成之后调用postRestart.

再经历3次(自定义策略配置的)重启以后,达到重启上限,系统将直接关闭该actor。

选择actor

上面程序中使用到了ActorSelection actorSelection = system.actorSelection("akka://strategy/user/SuperVisor/restartActor");进行actor的选择。
工作过程中可能会存在成千上万的actor,可以通过actorSelection方便的选择actor进行消息投递,其支持通配符匹配getContext().actorSelection("/user/worker_*").

参考资料

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

快乐崇拜234

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值