akka框架:(四)actor生命周期

转载:https://blog.csdn.net/liubenlong007/article/details/54093889

这里写图片描述

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();
        }
    }
}

 
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
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);
    }

  }

}


 
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
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());
  }
}
 
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

输出结果:

[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
 
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5

监督

这里可以对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() {
                    @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);
        }
    }
}

 
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

定义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 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);
        }

    }
}

 
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

定义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());
        }
    }

}

 
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

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

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)

 
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

结果分析:
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_*").

参考资料

  • 书籍《java高并发程序设计》
  • AKKA官方文档
  • 下一篇:inbox消息收件箱

你可能感兴趣的:(akka框架学习,akka框架学习,akka-actor生命周期)