akka的简单demo
1.概述
akka是actor模型的实现,可自行实现actor和beheavor。
2.简单demo
import akka.actor.typed.ActorRef; import akka.actor.typed.ActorSystem; import akka.actor.typed.Behavior; import akka.actor.typed.javadsl.AbstractBehavior; import akka.actor.typed.javadsl.ActorContext; import akka.actor.typed.javadsl.Behaviors; import akka.actor.typed.javadsl.Receive; public class PrintMyActorRefActor extends AbstractBehavior<String> { static Behavior<String> create() { return Behaviors.setup(PrintMyActorRefActor::new); } private PrintMyActorRefActor(ActorContext<String> context) { super(context); } @Override public Receive<String> createReceive() { return newReceiveBuilder().onMessageEquals("printit", this::printIt).build(); } private Behavior<String> printIt() { ActorRef<String> secondRef = getContext().spawn(Behaviors.empty(), "second-actor"); System.out.println("Second: " + secondRef); return this; } public static void main(String[] args) { ActorRef<String> testSystem = ActorSystem.create(Main.create(), "testSystem"); testSystem.tell("start"); } }
class Main extends AbstractBehavior<String> {
static Behavior<String> create() {
return Behaviors.setup(Main::new);
}
private Main(ActorContext<String> context) {
super(context);
}
@Override
public Receive<String> createReceive() {
return newReceiveBuilder().onMessageEquals("start", this::start).build();
}
private Behavior<String> start() {
ActorRef<String> firstRef = getContext().spawn(PrintMyActorRefActor.create(), "first-actor");
System.out.println("First: " + firstRef);
firstRef.tell("printit");
return Behaviors.same();
}
}
首先根节点的actor是testSystem,发送start消息后,根据消息匹配到start方法,start的方法是运行在新的actor中,路径是testSystem/start/first-actor,当需要向上游节点发送数据时需要将当前behavior添加actor参数。
import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.Set; import akka.actor.typed.ActorRef; import akka.actor.typed.Behavior; import akka.actor.typed.javadsl.*; import akka.actor.typed.receptionist.Receptionist; //#frontend public class Frontend extends AbstractBehavior<Frontend.Event> { interface Event {} private enum Tick implements Event { INSTANCE } private static final class WorkersUpdated implements Event { public final Set<ActorRef<Worker.TransformText>> newWorkers; public WorkersUpdated(Set<ActorRef<Worker.TransformText>> newWorkers) { this.newWorkers = newWorkers; } } private static final class TransformCompleted implements Event { public final String originalText; public final String transformedText; public TransformCompleted(String originalText, String transformedText) { this.originalText = originalText; this.transformedText = transformedText; } } private static final class JobFailed implements Event { public final String why; public final String text; public JobFailed(String why, String text) { this.why = why; this.text = text; } } public static Behavior<Event> create() { return Behaviors.setup(context -> Behaviors.withTimers(timers -> new Frontend(context, timers) ) ); } private final List<ActorRef<Worker.TransformText>> workers = new ArrayList<>(); private int jobCounter = 0; private Frontend(ActorContext<Event> context, TimerScheduler<Event> timers) { super(context); ActorRef<Receptionist.Listing> subscriptionAdapter = context.messageAdapter(Receptionist.Listing.class, listing -> new WorkersUpdated(listing.getServiceInstances(Worker.WORKER_SERVICE_KEY))); context.getSystem().receptionist().tell(Receptionist.subscribe(Worker.WORKER_SERVICE_KEY, subscriptionAdapter)); timers.startTimerWithFixedDelay(Tick.INSTANCE, Tick.INSTANCE, Duration.ofSeconds(2)); } @Override public Receive<Event> createReceive() { return newReceiveBuilder() .onMessage(WorkersUpdated.class, this::onWorkersUpdated) .onMessage(TransformCompleted.class, this::onTransformCompleted) .onMessage(JobFailed.class, this::onJobFailed) .onMessageEquals(Tick.INSTANCE, this::onTick) .build(); } private Behavior<Event> onTransformCompleted(TransformCompleted event) { getContext().getLog().info("Got completed transform of {}: {}", event.originalText, event.transformedText); return this; } private Behavior<Event> onJobFailed(JobFailed event) { getContext().getLog().warn("Transformation of text {} failed. Because: {}", event.text, event.why); return this; } private Behavior<Event> onTick() { if (workers.isEmpty()) { getContext().getLog().warn("Got tick request but no workers available, not sending any work"); } else { // how much time can pass before we consider a request failed Duration timeout = Duration.ofSeconds(5); ActorRef<Worker.TransformText> selectedWorker = workers.get(jobCounter % workers.size()); getContext().getLog().info("Sending work for processing to {}", selectedWorker); String text = "hello-" + jobCounter; getContext().ask( Worker.TextTransformed.class, selectedWorker, timeout, responseRef -> new Worker.TransformText(text, responseRef), (response, failure) -> { if (response != null) { return new TransformCompleted(text, response.text); } else { return new JobFailed("Processing timed out", text); } } ); jobCounter++; } return this; } private Behavior<Event> onWorkersUpdated(WorkersUpdated event) { workers.clear(); workers.addAll(event.newWorkers); getContext().getLog().info("List of services registered with the receptionist changed: {}", event.newWorkers); return this; } }
public class Worker {
public static ServiceKey<Worker.TransformText> WORKER_SERVICE_KEY =
ServiceKey.create(TransformText.class, "Worker");
interface Command extends CborSerializable {}
public static final class TransformText implements Command {
public final String text;
public TransformText(String text, ActorRef<TextTransformed> replyTo) {
this.text = text;
this.replyTo = replyTo;
}
public final ActorRef<TextTransformed> replyTo;
}
public static final class TextTransformed implements CborSerializable {
public final String text;
@JsonCreator
public TextTransformed(String text) {
this.text = text;
}
}
public static Behavior<Command> create() {
return Behaviors.setup(context -> {
context.getLog().info("Registering myself with receptionist");
context.getSystem().receptionist().tell(Receptionist.register(WORKER_SERVICE_KEY, context.getSelf().narrow()));
return Behaviors.receive(Command.class)
.onMessage(TransformText.class, command -> {
command.replyTo.tell(new TextTransformed(command.text.toUpperCase()));
return Behaviors.same();
}).build();
});
}
}