持续更新中….
目录
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 below
Props 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所有的路由都共享一个邮箱实例。