關于akka官方quickstart示例程序(scala)的記錄

參考資料

  • https://doc.akka.io/libraries/akka-core/current/typed/actors.html#first-example

關于scala語法的注意事項

  • extends App是個語法糖,等同于直接在伴生對象中編寫main 方法
  • 對象是通過apply方法創建的,也可以通過對象的名稱單獨創建(此時實際上會調用apply方法)
  • case class 樣例類用于定義不可變類,可以用于模式匹配
  • trait類似接口但是可以包括抽象方法,具體方法,子類。帶有sealed表示只能在定義它的同一個文件中被繼承,常用于更加安全的模式匹配,例如如果消息類型為sealed trait,則actor可以安全接受多種消息

helloworld示例

代碼的整體示意圖如下

hello-world2.png

  1. HelloWorldMain創建ActorSystem,作為一個actorref指向HelloWorldMain actor。使用此引用向HelloWorldMain actor發送SayHello消息
  2. HelloWorldMain actor初始化Helloworld actor和HelloWorldBot,以及在收到SayHello消息后向HelloWorld actor發送Greet消息(其中帶有HelloWorldBot的actorref)
  3. HelloWorld actor收到消息后向HelloWorldBot發送Greeted消息
  4. HelloWorldBot actor收到消息后greetingCounter計數增加,并向HelloWorld actor返回Greet消息。當greetingCounter超過max時暫停行為。

代碼示例

//#imports
import akka.actor.typed.ActorRef
import akka.actor.typed.ActorSystem
import akka.actor.typed.Behavior
import akka.actor.typed.scaladsl.Behaviors//#hello-world-actor
object HelloWorld {// 使用樣例類定義消息類型final case class Greet(whom: String, replyTo: ActorRef[Greeted])final case class Greeted(whom: String, from: ActorRef[Greet])// Behaviors.receive函數接收一個函數作為參數,{}是為了容納多行lambda表達式def apply(): Behavior[Greet] = Behaviors.receive { (context, message) =>context.log.info("Hello {}!", message.whom)message.replyTo ! Greeted(message.whom, context.self) // 向message.replyTo發送消息Greeted,其中context.self是自身的actorrefBehaviors.same // 設置后續的消息處理邏輯不變}
}//#hello-world-bot
object HelloWorldBot {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 + 1context.log.info("Greeting {} for {}", n, message.whom)if (n == max) {Behaviors.stopped // 到達max次數后停止行為,避免無限循環} else {message.from ! HelloWorld.Greet(message.whom, context.self)bot(n, max)}}
}//#hello-world-main
object HelloWorldMain {final case class SayHello(name: String)def apply(): Behavior[SayHello] =Behaviors.setup { context =>val greeter = context.spawn(HelloWorld(), "greeter") // 初始化HelloWorldBehaviors.receiveMessage { message => // 收到消息后創建HelloWorldBotval replyTo = context.spawn(HelloWorldBot(max = 3), message.name)greeter ! HelloWorld.Greet(message.name, replyTo)Behaviors.same}}def main(args: Array[String]): Unit = {val system: ActorSystem[HelloWorldMain.SayHello] =ActorSystem(HelloWorldMain(), "hello")system ! HelloWorldMain.SayHello("World")Thread.sleep(3000)system.terminate()}
}

chatroom示例

代碼的整體示意圖如下

chat-room.png

  1. Main啟動后,初始化chatRoom和Gabbler客戶端。向ChatRoom發送GetSession消息(帶有client actorref)
  2. chatRoom創建session actor,用來隔離會話
  3. chatRoom向client發送SessionGranted消息(帶有session actorref)
  4. client(Gabbler)收到SessionGranted后向session actor發送PostMessage消息
  5. session 收到SessionGranted后向room發送PublishSessionMessage
  6. room返回NotifyClient給session
  7. 然后按照NotifyClient(帶有MessagePosted)中的client actorref將MessagePosted轉發給特定的client
  8. client收到MessagePosted之后完成并推出

整體的思路

  1. ChatRoom Actor:作為中央樞紐,負責管理所有的會話(Sessions)。每個連接到聊天室的客戶端都會通過 GetSession 消息與 ChatRoom 交互,并獲得一個專屬的會話 Actor。
  2. Session Actor:每個客戶端都有一個對應的 Session Actor,用于處理該客戶端的消息收發、保持客戶端狀態等。
  3. client(Gabbler)Actor:模擬客戶端行為,可以發送消息給 ChatRoom 或者其他客戶端。
  4. 客戶端間通信:通過 ChatRoom 轉發消息來實現客戶端間的通信。當一個客戶端發送消息時,它實際上是將消息發送給了 ChatRoom,然后由 ChatRoom 將消息廣播給所有其他在線的客戶端。

代碼示例

定義消息,這里實際上等同于定義actor之間的通信協議

  • RoomCommand,用來獲取session
  • SessionEvent,用來管理session和發送message
  • SessionCommand,用來發送message和通知client
object ChatRoom {sealed trait RoomCommandfinal case class GetSession(screenName: String, replyTo: ActorRef[SessionEvent]) extends RoomCommandsealed trait SessionEventfinal case class SessionGranted(handle: ActorRef[PostMessage]) extends SessionEventfinal case class SessionDenied(reason: String) extends SessionEventfinal case class MessagePosted(screenName: String, message: String) extends SessionEventsealed trait SessionCommandfinal case class PostMessage(message: String) extends SessionCommandprivate final case class NotifyClient(message: MessagePosted) extends SessionCommand
}

ChatRoom actor部分

object ChatRoom {// PublishSessionMessage消息將包含的ChatRoom消息傳播到所有連接的客戶端private final case class PublishSessionMessage(screenName: String, message: String) extends RoomCommanddef apply(): Behavior[RoomCommand] =chatRoom(List.empty)private def chatRoom(sessions: List[ActorRef[SessionCommand]]): Behavior[RoomCommand] =Behaviors.receive { (context, message) =>message match {// 如果收到GetSession,create a child actor for further interaction with the clientcase GetSession(screenName, client) =>val ses = context.spawn(session(context.self, screenName, client),name = URLEncoder.encode(screenName, StandardCharsets.UTF_8.name))client ! SessionGranted(ses)chatRoom(ses :: sessions) // ::用于將ses添加到sessions頭。由于Akka 的行為是不可變的(每次更改狀態都必須返回一個新的 behavior),所以通常通過 遞歸函數 + 參數攜帶狀態 的方式來模擬“狀態變化”// 如果接收到 PublishSessionMessage 就向所有的session發送notification,每個session都帶有client內容。等于是申請chatroom允許發送case PublishSessionMessage(screenName, message) =>val notification = NotifyClient(MessagePosted(screenName, message))sessions.foreach(_ ! notification) // 將消息轉發給session中的所有clientBehaviors.same}}// 用于創建session actor,接受SessionCommand消息private def session(room: ActorRef[PublishSessionMessage],screenName: String,client: ActorRef[SessionEvent]): Behavior[SessionCommand] =Behaviors.receiveMessage {// 向room中的所有其他用戶發送消息case PostMessage(message) =>room ! PublishSessionMessage(screenName, message)Behaviors.same// room發布消息通知clientcase NotifyClient(message) =>client ! messageBehaviors.same}
}

客戶端部分

object Gabbler {import ChatRoom._def apply(): Behavior[SessionEvent] =Behaviors.setup { context =>Behaviors.receiveMessage {case SessionDenied(reason) =>context.log.info("cannot start chat room session: {}", reason)Behaviors.stoppedcase SessionGranted(handle) =>handle ! PostMessage("Hello World!")Behaviors.samecase MessagePosted(screenName, message) =>context.log.info("message has been posted by '{}': {}", screenName, message)Behaviors.stopped}}

actorsystem入口

  • 這里使用了Behaviors.setup。Behaviors.setupBehaviors.receiveMessage 都是用于定義 Actor 行為的工廠方法,區別是Behaviors.setup 允許你在初始化階段訪問 ActorContext,而 Behaviors.receiveMessage 不直接提供對上下文的訪問,專注于消息處理邏輯
  • Main Actor,對應于傳統 Java 應用程序中的 main 方法
object Main {def apply(): Behavior[NotUsed] =Behaviors.setup { context =>val chatRoom = context.spawn(ChatRoom(), "chatroom")val gabblerRef = context.spawn(Gabbler(), "gabbler")context.watch(gabblerRef) //監控gabbler actor,如果gabbler 終止了,當前 Actor 將收到一個 Terminated(gabblerRef) 信號chatRoom ! ChatRoom.GetSession("ol’ Gabbler", gabblerRef)// 處理 Terminated 信號Behaviors.receiveSignal {case (_, Terminated(_)) =>Behaviors.stopped}}def main(args: Array[String]): Unit = {ActorSystem(Main(), "ChatRoomDemo")}
}

運行結果如下,按照預期邏輯,目前只有一個client,并且發送消息收到響應后推出

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/85865.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/85865.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/85865.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

基于vue3-elemenyui的頁面加載及新建瀏覽頁案例

1.參考鏈接: 基于創建vue3鏈接:Vue3前端項目創建_vscode創建vue3項目-CSDN博客 基于創建elementui鏈接:Vue3引入ElementPlus_vue引入element-plus-CSDN博客 2.案例內容 該案例實現了基本的app.vue的路由跳轉、新建瀏覽頁參數傳入以及瀏覽…

板凳-------Mysql cookbook學習 (十)

5.6 改變字符串的字符集或字符排序 mysql> set s1 my string; Query OK, 0 rows affected (0.01 sec)mysql> set s2 convert(s1 using utf8); Query OK, 0 rows affected, 1 warning (0.00 sec)mysql> select charset(s1), charset(s2); -------------------------…

使用nginx配置反向代理,負載均衡

首先啥叫反向代理 咋配置呢,那當然是在nginx目錄下改conf文件了 具體咋改呢,那就新增一個新的server配置,然后在location里新增你想代理的服務器 實際上負載均衡也就是根據反向代理的思路來的,如下所示 配置的話實際上也與上…

嵌入式開發之STM32學習筆記day20

STM32F103C8T6 PWR電源控制 1 PWR簡介 PWR(Power Control)電源控制單元是STM32微控制器中一個重要的組成部分,它負責管理系統的電源管理功能,以優化功耗并提高效率。PWR負責管理STM32內部的電源供電部分,可以實現可編…

Spring AI(10)——STUDIO傳輸的MCP服務端

Spring AI MCP(模型上下文協議)服務器Starters提供了在 Spring Boot 應用程序中設置 MCP 服務器的自動配置。它支持將 MCP 服務器功能與 Spring Boot 的自動配置系統無縫集成。 本文主要演示支持STDIO傳輸的MCP服務器 僅支持STDIO傳輸的MCP服務器 導入j…

Java八股文——集合「Set篇」

Set集合有什么特點?如何實現key無重復的? 面試官您好,Set 集合是 Java 集合框架中的一個重要接口,它繼承自 Collection 接口,其最顯著的特點和設計目標就是存儲一組不重復的元素。 一、Set集合的主要特點&#xff1a…

「數據分析 - NumPy 函數與方法全集」【數據分析全棧攻略:爬蟲+處理+可視化+報告】

- 第 104 篇 - Date: 2025 - 06 - 05 Author: 鄭龍浩/仟墨 NumPy 函數與方法全集 文章目錄 NumPy 函數與方法全集1. 數組創建與初始化基礎創建序列生成特殊數組 2. 數組操作形狀操作合并與分割 3. 數學運算基礎運算統計運算 4. 隨機數生成基礎隨機分布函數 5. 文件IO文件讀寫 …

報表/報告組件(二)-實例與實現解釋

上篇《報表/報告組件(一)-指標/屬性組件設計》介紹了組件核心指標/屬性設計,本文以實例介紹各個特性的實現和效果,實例是多個報告融合,顯示所有的特性。 設計 指標/屬性組件是報告/報表關鍵部分,上篇已介紹過,本節回顧…

Flutter嵌入式開發實戰 ——從樹莓派到智能家居控制面板,打造工業級交互終端

一、為何選擇Flutter開發嵌入式設備&#xff1f; 1. 跨平臺能力降維打擊 特性傳統方案Flutter方案開發效率需分別開發Android/Linux一套代碼多端部署內存占用200MB (QtWeb引擎)<80MB (Release模式)熱重載支持不支持支持 2. 工業級硬件支持實測 樹莓派4B&#xff1a;1080…

[藍橋杯]機器人塔

題目描述 X 星球的機器人表演拉拉隊有兩種服裝&#xff0c;A 和 B。 他們這次表演的是搭機器人塔。 類似&#xff1a; A B B A B A A A B B B B B A B A B A B B A 隊內的組塔規則是&#xff1a; A 只能站在 AA 或 BB 的肩上。 B 只能站在 AB 或 BA 的肩上。 你的…

語雀文檔保存失敗URI malformed

原因 原因未知&#xff0c;我用deekseek將回答的答案復制到語雀文檔時出現了這個異常&#xff0c;在知識庫里面一直保存失敗 語雀文檔保存失敗URI malformed 解決方案 使用小記&#xff0c;將里面的內容轉移到小記里&#xff0c;將小記移到知識庫中即可

小明的Java面試奇遇之互聯網保險系統架構與性能優化

一、文章標題 小明的Java面試奇遇之互聯網保險系統架構與性能優化&#x1f680; 二、文章標簽 Java,Spring Boot,MyBatis,Redis,Kafka,JVM,多線程,互聯網保險,系統架構,性能優化 三、文章概述 本文模擬了程序員小明在應聘互聯網保險系統開發崗位時&#xff0c;參與的一場深…

從零開始的嵌入式學習day33

網絡編程及相關概念 UDP網絡通信程序 UDP網絡通信操作 一、網絡編程及相關概念 1. 網絡編程概念&#xff1a; 指通過計算機網絡實現程序間通信的技術&#xff0c;涉及協議、套接字、數據傳輸等核心概念。常見的應用場景包括客戶端-服務器模型、分布式系統、實時通信等。…

Kotlin 1. 搭建Kotlin開發環境

本實戰概述旨在指導用戶搭建Kotlin開發環境&#xff0c;并進行簡單的編程實踐。首先&#xff0c;用戶需安裝IntelliJ IDEA&#xff0c;并進行基本設置&#xff0c;如選擇主題、調整字體和安裝插件等。接著&#xff0c;創建Kotlin項目&#xff0c;設置項目名稱、位置和JDK版本&a…

Mysql的B-樹和B+樹的區別總結

B 樹也稱 B- 樹&#xff0c;全稱為 多路平衡查找樹&#xff0c;B 樹是 B 樹的一種變體。B 樹和 B 樹中的 B 是 Balanced&#xff08;平衡&#xff09;的意思。 目前大部分數據庫系統及文件系統都采用 B-Tree 或其變種 BTree 作為索引結構。 B 樹& B 樹兩者有何異同呢&…

COMSOL學習筆記-靜電場仿真

最近在學習COMSOL&#xff0c;做了一個靜電場仿真的例子&#xff0c;分享一下。 參考了下面的官方案例 計算電容 電容式位置傳感器的邊界元建模 三維模型 首先對靜電測試儀進行三維建模。 Comsol靜電場仿真 使用comsol進行靜電場仿真&#xff0c;控制方程為泊松方程&#…

JavaScript 循環方法對比指南

JavaScript 循環方法對比指南 1. 標準 for 循環 語法&#xff1a; for (let i 0; i < arr.length; i) {console.log(arr[i]); }優點 ? 完全控制索引&#xff0c;適合需要精確控制遍歷順序或步長的場景。 ? 性能最優&#xff0c;在超大規模數據遍歷時比高階方法&#x…

【快餐點餐簡易軟件】佳易王快餐店點餐系統軟件功能及操作教程

一、軟件概述與核心優勢 &#xff08;一&#xff09;試用版獲取方式 資源下載路徑&#xff1a;進入博主頭像主頁第一篇文章末尾&#xff0c;點擊卡片按鈕&#xff1b;或訪問左上角博客主頁&#xff0c;通過右側按鈕獲取詳細資料。 說明&#xff1a;下載文件為壓縮包&#xff…

智慧園區數字孿生全鏈交付方案:降本增效30%,多案例實踐驅動全周期交付

在智慧園區建設浪潮中&#xff0c;數字孿生技術正成為破解傳統園區管理難題的核心引擎。通過構建與物理園區1:1映射的數字模型&#xff0c;實現數據集成、狀態同步與智能決策&#xff0c;智慧園區數字孿生全鏈交付方案已在多個項目中驗證其降本增效價值——某物流園區通過該方案…

從0開始學vue:Element Plus詳解

一、核心架構解析二、技術實現指南三、高級特性實現四、性能優化方案五、生態擴展方案六、調試與測試七、版本演進路線 Element Plus 是專為 Vue 3 設計的桌面端 UI 組件庫&#xff0c;基于 Vue 3 的 Composition API 重構&#xff0c;在保持與 Element UI 兼容性的同時&#x…