Akka Actors入门案例解析
1. HelloWorld
import akka.actor.typed.scaladsl.Behaviors import akka.actor.typed.scaladsl.LoggerOps import akka.actor.typed.{ActorRef, ActorSystem, Behavior}object HelloWorld {/*** 某人打招呼** @param whom 誰(某人)* @param replyTo 消息的回復者*/final case class Greet(whom: String, replyTo: ActorRef[Greeted])/*** 確認已打過招呼** @param whom 誰* @param from 來自哪里(發送者)*/final case class Greeted(whom: String, from: ActorRef[Greet])/*** 默認執行方法,響應 Greet** @return*/def apply(): Behavior[Greet] = Behaviors.receive {(context, message) =>// 發送消息context.log.info("發送消息 => Hello {}!", message.whom)// 回復已經收到消息message.replyTo ! Greeted(message.whom , context.self)// 行為重用Behaviors.same} }object HelloWorldBot {/*** 響應 Greeted** @param max 總問候次數* @return*/def apply(max: Int): Behavior[HelloWorld.Greeted] = {bot(0, max)}private def bot(greetingCounter: Int, max: Int): Behavior[HelloWorld.Greeted] =Behaviors.receive { (context, message) =>val n = greetingCounter + 1// 收到消息context.log.info2("收到消息 => Greeting {} for {}", n, message.whom)if (n == max) {// 達到總數時,停止。Behaviors.stopped} else {message.from ! HelloWorld.Greet(message.whom+ " 回復 ", context.self)bot(n, max)}} }object HelloWorldMain {// 入口final case class SayHello(name: String)def apply(): Behavior[SayHello] =Behaviors.setup { context =>// 從給定的行為并給定名稱創建子Actorval greeter = context.spawn(HelloWorld(), "greeter")// 創建簡單的參與者Behaviors.receiveMessage { message =>val replyTo = context.spawn(HelloWorldBot(max = 3), message.name)greeter ! HelloWorld.Greet(message.name, replyTo)Behaviors.same}}}object Main extends App {val system: ActorSystem[HelloWorldMain.SayHello] =ActorSystem(HelloWorldMain(), "hello")system ! HelloWorldMain.SayHello("World")system ! HelloWorldMain.SayHello("Akka") }響應打招呼信息
object HelloWorld {/*** 某人打招呼** @param whom 誰(某人)* @param replyTo 消息的回復者*/final case class Greet(whom: String, replyTo: ActorRef[Greeted])/*** 確認已打過招呼** @param whom 誰* @param from 來自哪里(發送者)*/final case class Greeted(whom: String, from: ActorRef[Greet])/*** 默認執行方法,響應 Greet** @return*/def apply(): Behavior[Greet] = Behaviors.receive {(context, message) =>// 發送消息context.log.info("發送消息 => Hello {}!", message.whom)// 回復已經收到消息message.replyTo ! Greeted(message.whom , context.self)// 行為重用Behaviors.same} }定義了兩個消息類 Greet、Greeted
Behavior[T]
The behavior of an actor defines how it reacts to the messages that it receives. The message may either be of the type that the Actor declares and which is part of the ActorRef signature, or it may be a system Signal that expresses a lifecycle event of either this actor or one of its child actors.
Behaviors can be formulated in a number of different ways, either by using the DSLs in akka.actor.typed.scaladsl.Behaviors and akka.actor.typed.javadsl.Behaviors or extending the abstract ExtensibleBehavior class.
Closing over ActorContext makes a Behavior immobile: it cannot be moved to another context and executed there, and therefore it cannot be replicated or forked either.
This base class is not meant to be extended by user code. If you do so, you may lose binary compatibility.
Not for user extension.
actor的行為定義了它對收到的消息的反應。 該消息可以是Actor聲明的類型,并且是ActorRef簽名的一部分,也可以是表示該Actor或其子Actor的生命周期事件的系統Signal。
可以通過使用akka.actor.typed.scaladsl.Behaviors和akka.actor.typed.javadsl.Behaviors中的DSL或擴展抽象的ExtensibleBehavior類來以多種不同方式來表示行為。
在ActorContext上關閉將使行為不可移動:無法將其移動到另一個上下文并在該上下文中執行,因此也無法復制或分支它。
此基類并不打算由用戶代碼擴展。 如果這樣做,則可能會失去二進制兼容性。
不用于用戶擴展。
消息訂閱
Behaviors.receive
Construct an actor behavior that can react to both incoming messages and lifecycle signals. After spawning this actor from another actor (or as the guardian of an ActorSystem) it will be executed within an ActorContext that allows access to the system, spawning and watching other actors, etc.
Compared to using AbstractBehavior this factory is a more functional style of defining the Behavior. Processing the next message results in a new behavior that can potentially be different from this one. State is maintained by returning a new behavior that holds the new immutable state.
構造一個既可以對傳入消息又可以對生命周期信號做出反應的參與者行為。 從另一個角色(或作為ActorSystem的守護者)派生此actor之后,它將在ActorContext中執行,該ActorContext允許訪問系統,派生和觀看其他actor等。
與使用AbstractBehavior相比,該工廠是定義行為的更具功能性的樣式。 處理下一條消息會導致一種新行為,該行為可能與此行為有所不同。 通過返回擁有新的不可變狀態的新行為來維護狀態。
構造一個既可以對傳入消息又可以對生命周期信號做出反應的參與者。
def self: ActorRef[T]
The identity of this Actor, bound to the lifecycle of this Actor instance. An Actor with the same name that lives before or after this instance will have a different ActorRef.
This field is thread-safe and can be called from other threads than the ordinary actor message processing thread, such as Future callbacks.
此Actor的身份,綁定到此Actor實例的生命周期。 在此實例之前或之后存在的同名Actor將具有不同的ActorRef。
該字段是線程安全的,可以從普通actor消息處理線程以外的其他線程中調用,例如Future回調。
def !(msg: T): Unit = ref.tell(msg)
Send a message to the Actor referenced by this ActorRef using at-most-once messaging semantics.
使用“至多一次”消息傳遞語義將消息發送到此ActorRef引用的Actor。
Behaviors.same
Return this behavior from message processing in order to advise the system to reuse the previous behavior. This is provided in order to avoid the allocation overhead of recreating the current behavior where that is not necessary.
從消息處理中返回此行為,以建議系統重用以前的行為。 提供此功能是為了避免不必要的重新創建當前行為的分配開銷。
響應回復消息
object HelloWorldBot {/*** 響應 Greeted** @param max 總問候次數* @return*/def apply(max: Int): Behavior[HelloWorld.Greeted] = {bot(0, max)}private def bot(greetingCounter: Int, max: Int): Behavior[HelloWorld.Greeted] =Behaviors.receive { (context, message) =>val n = greetingCounter + 1// 收到消息context.log.info2("收到消息 => Greeting {} for {}", n, message.whom)if (n == max) {// 達到總數時,停止。Behaviors.stopped} else {message.from ! HelloWorld.Greet(message.whom+ " 回復 ", context.self)bot(n, max)}} }Behaviors.stopped
Return this behavior from message processing to signal that this actor shall terminate voluntarily. If this actor has created child actors then these will be stopped as part of the shutdown procedure.
The PostStop signal that results from stopping this actor will be passed to the current behavior. All other messages and signals will effectively be ignored.
從消息處理中返回此行為,以表示該參與者應自愿終止。 如果此角色已創建子角色,則這些子角色將作為關閉過程的一部分而停止。
停止此參與者所產生的PostStop信號將傳遞給當前行為。 所有其他消息和信號將被有效忽略。
入口
object HelloWorldMain {// 入口final case class SayHello(name: String)def apply(): Behavior[SayHello] =Behaviors.setup { context =>// 從給定的行為并給定名稱創建子Actorval greeter = context.spawn(HelloWorld(), "greeter")// 創建簡單的參與者Behaviors.receiveMessage { message =>val replyTo = context.spawn(HelloWorldBot(max = 3), message.name)greeter ! HelloWorld.Greet(message.name, replyTo)Behaviors.same}}}def spawn[U](behavior: Behavior[U], name: String, props: Props = Props.empty): ActorRef[U]
Create a child Actor from the given Behavior and with the given name.
Warning: This method is not thread-safe and must not be accessed from threads other than the ordinary actor message processing thread, such as Future callbacks.
從給定的行為并給定名稱創建子Actor。
警告:此方法不是線程安全的,并且不能從普通actor消息處理線程以外的線程(例如Future回調)中訪問。
中轉
Behaviors.receiveMessage
Simplified version of Behaviors.Receive with only a single argument - the message to be handled. Useful for when the context is already accessible by other means, like being wrapped in an setup or similar.
Construct an actor behavior that can react to both incoming messages and lifecycle signals. After spawning this actor from another actor (or as the guardian of an ActorSystem) it will be executed within an ActorContext that allows access to the system, spawning and watching other actors, etc.
Compared to using AbstractBehavior this factory is a more functional style of defining the Behavior. Processing the next message results in a new behavior that can potentially be different from this one. State is maintained by returning a new behavior that holds the new immutable state.
行為的簡化版本。僅使用一個參數即可接收-要處理的消息。 當上下文已經可以通過其他方式訪問時有用,例如包裝在設置中或類似內容中。
構造一個既可以對傳入消息又可以對生命周期信號做出反應的參與者行為。 從另一個角色(或作為ActorSystem的守護者)派生此actor之后,它將在ActorContext中執行,該ActorContext允許訪問系統,派生和觀看其他actor等。
與使用AbstractBehavior相比,該工廠是定義行為的更具功能性的樣式。 處理下一條消息會導致一種新行為,該行為可能與此行為有所不同。 通過返回擁有新的不可變狀態的新行為來維護狀態。
行為的簡化版本,少了 context
運行
object Main extends App {val system: ActorSystem[HelloWorldMain.SayHello] =ActorSystem(HelloWorldMain(), "hello")system ! HelloWorldMain.SayHello("World")system ! HelloWorldMain.SayHello("Akka") }運行結果
2020-10-29 11:28:12.458 INFO --- [lt-dispatcher-7] HelloWorld$ : 發送消息 => Hello World! 2020-10-29 11:28:12.459 INFO --- [lt-dispatcher-7] HelloWorld$ : 發送消息 => Hello Akka! 2020-10-29 11:28:12.460 INFO --- [lt-dispatcher-7] HelloWorldBot$ : 收到消息 => Greeting 1 for Akka 2020-10-29 11:28:12.460 INFO --- [lt-dispatcher-7] HelloWorld$ : 發送消息 => Hello Akka 回復 ! 2020-10-29 11:28:12.460 INFO --- [lt-dispatcher-7] HelloWorldBot$ : 收到消息 => Greeting 2 for Akka 回復 2020-10-29 11:28:12.460 INFO --- [lt-dispatcher-7] HelloWorld$ : 發送消息 => Hello Akka 回復 回復 ! 2020-10-29 11:28:12.460 INFO --- [lt-dispatcher-7] HelloWorldBot$ : 收到消息 => Greeting 3 for Akka 回復 回復 2020-10-29 11:28:12.460 INFO --- [lt-dispatcher-6] HelloWorldBot$ : 收到消息 => Greeting 1 for World 2020-10-29 11:28:12.462 INFO --- [lt-dispatcher-6] HelloWorld$ : 發送消息 => Hello World 回復 ! 2020-10-29 11:28:12.463 INFO --- [lt-dispatcher-6] HelloWorldBot$ : 收到消息 => Greeting 2 for World 回復 2020-10-29 11:28:12.463 INFO --- [lt-dispatcher-6] HelloWorld$ : 發送消息 => Hello World 回復 回復 ! 2020-10-29 11:28:12.464 INFO --- [lt-dispatcher-3] HelloWorldBot$ : 收到消息 => Greeting 3 for World 回復 回復2. ChatRoom
博客遷移
總結
以上是生活随笔為你收集整理的Akka Actors入门案例解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 阿里云OSS线程增长问题分析
- 下一篇: Actors 介绍