Akka学习笔记

来源:互联网 发布:打字赚钱的软件 编辑:程序博客网 时间:2024/05/16 15:49

持续更新中….
目录

  • Akka官网
  • Part 1 Actor结构
    • Actor的层次结构
    • Actor的生命周期
    • 失败处理
  • Part 2 Actors
    • 创建Actors
      • 定义一个Actor类
      • Props
      • 使用Props创建Actors
      • 依赖注入
      • Inbox
    • Actor API
      • ActorSelection
      • Lifecycle Monitoring aka DeathWatch
    • Identifying Actors via Actor Selection
    • 消息和不变性Immutability
    • 发送消息
    • 接收消息
    • 接收超时时间
    • 关闭Actor
      • PoisonPill
      • 杀死Actor
      • 优雅的关闭
    • BecomeUnbecome
    • Stash
  • Part3 Dispatchers
  • Part4 Mailboxes
    • Mailbox Selection
  • Part5 Routes

Akka官网

https://doc.akka.io/docs/akka/current/guide

Part 1 Actor结构

Actor的层次结构

这里写图片描述
所有的Actor都有一个父级Actor,system.actorOf()方法在/user目录下创建Actor,contextOf()方法在父级Actor下创建Actor。

Actor的生命周期

这里写图片描述
当一个actor被关闭时,它的所有子节点也将会被递归地关闭。这样可以很好的避免资源的浪费还有资源的泄露,例如当子节点中有一些打开的socket或者文件。事实上,在处理低层次的多线程代码时,一个通常被忽视的困难是各种并发资源的生命周期管理。

为了停止一个参与者,推荐的模式是调用getContext().stop(getSelf())在actor中停止自身,通常作为对某个用户定义的停止消息的响应,或者当参与者完成它的工作时。从技术上讲,通过调用getContext().stop(actorRef)来阻止另一个参与者是可行的,但是阻止任意的行为者被认为是一种不好的做法:尝试给他们发送一个PoisonPill或自定义的停止消息,让收到消息的Actor自己停止。

Akka actor API公开了许多可以在actor实现中覆盖的生命周期hooks。最常用的是preStart()和postStop()。

  • preStart():在Actor开始之后,处理第一条消息之前调用

  • postStop():在Actor停止之后条用,一旦调用,将不会处理任何消息

失败处理

一旦一个actor出错(抛出一个异常或者在receive方法中抛出)它会暂停,子级的错误会抛给父级,然后父级觉得如何处理异常,父级是作为子级的监视者,Akka提供的默认的监视策略是停止子级然后重启它。

Part 2 Actors

Actor模型对于高并发的分布式系统提供了更高层次的抽象。它让开发者可以避免显式的使用锁和管理线程,使得开发一个正确的并发系统更加容易。

创建Actors

定义一个Actor类

import akka.actor.AbstractActor;import akka.event.Logging;import akka.event.LoggingAdapter;public class MyActor extends AbstractActor {  private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);  @Override  public Receive createReceive() {    return receiveBuilder()      .match(String.class, s -> {        log.info("Received String message: {}", s);      })      .matchAny(o -> log.info("received unknown message"))      .build();  }}

Props

Props是一个配置类用于创建actor时提供具体的参数

import akka.actor.Props;Props props1 = Props.create(MyActor.class);Props props2 = Props.create(ActorWithArgs.class,  () -> new ActorWithArgs("arg")); // careful, see belowProps props3 = Props.create(ActorWithArgs.class, "arg");

区别???待解决

使用Props创建Actors

通过将Props的实例传给ActorSystem或者ActorContext的工厂方法ActorOf来创建Actors。

import akka.actor.ActorRef;import akka.actor.ActorSystem;public class FirstActor extends AbstractActor {  final ActorRef child = getContext().actorOf(Props.create(MyActor.class), "myChild");  @Override  public Receive createReceive() {    return receiveBuilder()      .matchAny(x -> getSender().tell(x, getSelf()))      .build();  }}

调用actorOf方法返回的是ActorRef的实例,他是actor实例的引用,是唯一操作Actor的方法。

依赖注入

Inbox

Actor API

ActorSelection

Lifecycle Monitoring aka DeathWatch

为了在另一个Actor终止(即永久停止,而不是临时失败和重新启动)时被通知,Actor可以注册自己,以接收由另一个Actor在终止时发送的终止消息。该服务由actorSystem的DeathWatch组件提供。

import akka.actor.Terminated;public class WatchActor extends AbstractActor {  private final ActorRef child = getContext().actorOf(Props.empty(), "target");  private ActorRef lastSender = system.deadLetters();  public WatchActor() {    getContext().watch(child); // <-- this is the only call needed for registration  }  @Override  public Receive createReceive() {    return receiveBuilder()      .matchEquals("kill", s -> {        getContext().stop(child);        lastSender = getSender();      })      .match(Terminated.class, t -> t.actor().equals(child), t -> {        lastSender.tell("finished", getSelf());      })      .build();  }}

也可以通过使用context.unwatch(target)来观察另一个Actor的活动轨迹。即使已终止的消息已经在邮箱中被排队,它也能正常工作;在调用unwatch后,将不再处理该actor的终止消息。

Identifying Actors via Actor Selection

消息和不变性(Immutability)

重要:消息可以是任何类型的对象,但是必须是不可变的,虽然Akka框架并没有在代码上强制要求。

发送消息

可以使用下面两个方法去发送消息:
- tell:是“fire-and-forget”模式,既异步的发送消息,然后立即返回
- ask:异步发送消息,然后返回一个代表返回值的Future对象

接收消息

接收超时时间

public class ReceiveTimeoutActor extends AbstractActor {  public ReceiveTimeoutActor() {    // To set an initial delay    getContext().setReceiveTimeout(Duration.create(10, TimeUnit.SECONDS));  }  @Override  public Receive createReceive() {    return receiveBuilder()      .matchEquals("Hello", s -> {        // To set in a response to a message        getContext().setReceiveTimeout(Duration.create(1, TimeUnit.SECONDS));      })      .match(ReceiveTimeout.class, r -> {        // To turn it off        getContext().setReceiveTimeout(Duration.Undefined());      })      .build();  }}

关闭Actor

import akka.actor.ActorRef;import akka.actor.AbstractActor;public class MyStoppingActor extends AbstractActor {  ActorRef child = null;  // ... creation of child ...  @Override  public Receive createReceive() {    return receiveBuilder()      .matchEquals("interrupt-child", m ->        getContext().stop(child)      )      .matchEquals("done", m ->        getContext().stop(getSelf())      )      .build();  }}

PoisonPill

你也可以发送一个akka.actor.PoisonPill。毒丸消息,当消息被处理时,它将停止Actor。毒丸作为普通消息排队,并将在邮箱中已经排队的消息后处理。

victim.tell(akka.actor.PoisonPill.getInstance(), ActorRef.noSender());

杀死Actor

你也可以发送一个Kill消息,它和毒丸消息不一样会抛出一个异常,这个Actor将会暂停操作,它的监视者将会被调用去处理这个异常,也许是恢复,重启或者完全关闭它。

victim.tell(akka.actor.Kill.getInstance(), ActorRef.noSender());// expecting the actor to indeed terminate:expectTerminated(Duration.create(3, TimeUnit.SECONDS), victim);

优雅的关闭

如果你需要等待终止或组合多个参与者的命令终止,那么gracefulStop方法是非常有用的。

try {  CompletionStage<Boolean> stopped =    gracefulStop(actorRef, Duration.create(5, TimeUnit.SECONDS), Manager.SHUTDOWN);  stopped.toCompletableFuture().get(6, TimeUnit.SECONDS);  // the actor has been stopped} catch (AskTimeoutException e) {  // the actor wasn't stopped within 5 seconds}

Become/Unbecome

Stash

Part3 Dispatchers

Part4 Mailboxes

一个Akka的邮箱保存着相应Actor的消息,通常来说,每个Actor都有自己的邮箱,但是一个BalancingPool所有的路由都共享一个邮箱实例。

Mailbox Selection

Part5 Routes