Go语言事件总线EventBus本地事件总线系统的完整实现框架

在Go语言中,EventBus是一种非常有用的工具,它通过事件驱动的编程方式,帮助开发者实现组件之间的解耦,提高代码的可维护性和扩展性。

背景

  • 软件架构的发展需求:随着软件系统的规模和复杂度不断增大,传统的紧耦合架构在开发、测试、部署和维护等方面都面临着诸多挑战。组件之间的高度依赖使得代码难以修改和扩展,一旦某个组件发生变化,可能需要修改多个相关联的组件。EventBus所代表的事件驱动架构应运而生,它允许组件之间通过事件进行松散耦合的通信,降低了组件之间的依赖关系,使得系统更加灵活和可维护。

  • Go语言的并发特性:Go语言以其强大的并发能力而闻名,goroutine的轻量级和高效的特性使得并发编程变得简单而高效。EventBus与Go语言的并发特性相结合,可以更好地实现异步事件处理,充分发挥Go语言在高并发场景下的优势,提高系统的响应性和吞吐量。

  • 微服务架构的兴起:在微服务架构中,系统被拆分成多个小型的、独立的服务,这些服务之间需要进行高效的通信和协作。EventBus提供了一种轻量级的通信机制,使得微服务之间可以通过发布和订阅事件来实现解耦的交互,避免了服务之间的直接依赖,同时也支持异步的消息传递,提高了系统的可用性和可扩展性。

简介

  • 基本概念:EventBus是一种设计模式,它充当一个中央集散地,负责在事件的发布者和订阅者之间进行消息的传递。在Go语言中,通过使用EventBus库,开发者可以轻松地实现事件的发布、订阅和处理。当某个事件发生时,发布者将事件发送到EventBus,EventBus根据事件的类型或主题,将事件通知给所有订阅了该事件的订阅者,订阅者接收到事件后执行相应的处理逻辑。

  • 主要功能:提供了事件的发布与订阅功能,使得组件之间可以通过事件进行通信,而无需直接调用彼此的方法。支持异步事件处理,订阅者可以根据需要选择同步或异步的方式来处理事件,从而提高系统的响应速度和并发性能。具备事件的过滤和路由功能,可以根据事件的类型、主题或其他条件,将事件精准地分发给感兴趣的订阅者,提高事件处理的效率和准确性。

  • 优势:解耦组件之间的依赖关系,使得各个组件可以独立开发、测试和部署,提高了代码的可维护性和可扩展性。简化了事件驱动编程的实现,通过简单的API调用,就可以实现事件的发布和订阅,降低了开发难度和工作量。支持异步消息处理,可以提高系统的响应性和吞吐量,适用于高并发场景。提供了灵活的事件处理机制,可以满足不同类型和复杂度的业务需求,如支持多种事件类型、通配符订阅等。

安装

确保您的计算机上安装了 Go。 在终端中键入以下命令:

go get github.com/asaskevich/EventBus

之后,就可以在使用EventBus的时候导入包了。

使用

在文件中添加以下行:*.go

import "github.com/asaskevich/EventBus"

如果你不喜欢使用 long ,你可以对其进行起别名来处理:

import (evbus "github.com/asaskevich/EventBus"
)

简单案例

package mainimport ("fmt""github.com/asaskevich/EventBus"
)func calculator(a int, b int) {fmt.Printf("%d\n", a+b)
}func main() {bus := EventBus.New()err := bus.Subscribe("main:calculator", calculator)if err != nil {fmt.Printf("订阅事件 %s 失败: %v\n", "main:calculator", err)}bus.Publish("main:calculator", 20, 40)err = bus.Unsubscribe("main:calculator", calculator)if err != nil {fmt.Printf("取消订阅事件 %s 失败: %v\n", "main:calculator", err)}
}

如果你想要面向对象编程进行学习的话,可以对其进行封装处理:

package mainimport ("fmt""github.com/asaskevich/EventBus"
)type Bus struct {EventBus EventBus.Bus
}func calculator(a int, b int) {fmt.Printf("a + b = "+"%d\n", a+b)
}// Subscribe 方法注册事件监听
func (bus *Bus) Subscribe() {err := bus.EventBus.Subscribe("main:calculator", calculator)if err != nil {fmt.Printf("订阅事件 %s 失败: %v\n", "main:calculator", err)}
}// Publish 方法触发事件
func (bus *Bus) Publish() {bus.EventBus.Publish("main:calculator", 33, 60)
}// UnSubscribe 取消订阅
func (bus *Bus) UnSubscribe() {err := bus.EventBus.Unsubscribe("main:calculator", calculator)if err != nil {fmt.Printf("取消订阅事件 %s 失败: %v\n", "main:calculator", err)}
}func main() {eventBus := EventBus.New()bus := &Bus{EventBus: eventBus}bus.Subscribe()bus.Publish()bus.UnSubscribe()
}

方法

  • New()
  • Subscribe()
  • SubscribeOnce()
  • Unsubscribe()
  • HasCallback()
  • Publish()
  • SubscribeAsync()
  • SubscribeOnceAsync()
  • WaitAsync()

New()

函数签名

func New() EventBus

功能

创建一个新的事件总线实例,该实例用于管理事件的订阅、发布等操作。

应用场景

在需要使用事件总线机制的程序开始时调用,初始化事件总线。

示例代码

package mainimport ("github.com/asaskevich/EventBus"
)func main() {bus := EventBus.New() // 创建事件总线实例// 后续可使用 bus 进行事件订阅和发布操作
}

 Subscribe()

函数签名

func (bus *EventBus) Subscribe(topic string, fn interface{}) error

功能

将一个回调函数订阅到指定的事件主题上。当该主题的事件被发布时,回调函数会被同步调用。

应用场景

适用于需要同步处理事件的场景,例如更新界面状态、记录日志等。

返回错误

如果第二个参数传的不是函数,则会返回错误。

示例代码

package mainimport ("fmt""github.com/asaskevich/EventBus"
)func calculator(a int, b int) {fmt.Printf("%d\n", a+b)
}func main() {bus := EventBus.New()err := bus.Subscribe("main:calculator", calculator)if err != nil {fmt.Printf("订阅事件 %s 失败: %v\n", "main:calculator", err)}bus.Publish("main:calculator", 20, 40)
}

 SubscribeOnce()

函数签名

func (bus *EventBus) SubscribeOnce(topic string, fn interface{}) error

功能

将一个回调函数订阅到指定的事件主题上,该回调函数只会在事件第一次发布时被调用,之后自动取消订阅。

应用场景

适用于只需要处理一次事件的场景,例如初始化操作、一次性通知等。

返回错误

如果第二个参数传的不是函数,则会返回错误。

示例代码

package mainimport ("fmt""github.com/asaskevich/EventBus"
)func calculator(a int, b int) {fmt.Printf("%d\n", a+b)
}func main() {bus := EventBus.New()err := bus.SubscribeOnce("main:calculator", calculator)if err != nil {fmt.Printf("订阅事件 %s 失败: %v\n", "main:calculator", err)}bus.Publish("main:calculator", 20, 40)bus.Publish("main:calculator", 20, 40)  // 第二次发布,calculator不会再执行
}

Unsubscribe()

函数签名

func (bus *EventBus) Unsubscribe(topic string, fn interface{}) error

功能

从指定的事件主题中取消订阅指定的回调函数。

应用场景

当不再需要处理某个事件时,调用该函数取消订阅,释放资源。

返回错误

  1. 事件名称不存在:当你尝试取消订阅一个从未被订阅过的事件名称时,Unsubscribe 会返回错误。
  2. 处理函数不匹配:若你尝试用一个和订阅时不同的处理函数来取消订阅,Unsubscribe 也会返回错误。

示例代码

package mainimport ("fmt""github.com/asaskevich/EventBus"
)func calculator(a int, b int) {fmt.Printf("%d\n", a+b)
}func main() {bus := EventBus.New()err := bus.Subscribe("main:calculator", calculator)if err != nil {fmt.Printf("订阅事件 %s 失败: %v\n", "main:calculator", err)}err = bus.Unsubscribe("main:calculator", calculator)if err != nil {fmt.Printf("取消订阅事件 %s 失败: %v\n", "main:calculator", err)}bus.Publish("main:calculator", 20, 40) // 发布事件,calculator 不会再执行
}

HasCallback()

函数签名

func (bus *EventBus) HasCallback(topic string) bool

功能

检查指定的事件主题是否存在已订阅的回调函数。

应用场景

在发布事件前检查是否有订阅者,避免不必要的发布操作;或者在取消订阅前确认是否有回调函数需要取消。

示例代码

package mainimport ("fmt""github.com/asaskevich/EventBus"
)func calculator(a int, b int) {fmt.Printf("%d\n", a+b)
}func main() {bus := EventBus.New()// 订阅事件err := bus.Subscribe("main:calculator", calculator)if err != nil {fmt.Printf("订阅事件 %s 失败: %v\n", "main:calculator", err)return}// 检查是否有订阅者if bus.HasCallback("main:calculator") {// 有订阅者,发布事件bus.Publish("main:calculator", 20, 40)} else {fmt.Println("没有订阅者,不发布事件")}// 取消订阅err = bus.Unsubscribe("main:calculator", calculator)if err != nil {fmt.Printf("取消订阅事件 %s 失败: %v\n", "main:calculator", err)}
}

Publish()

函数签名

func (bus *EventBus) Publish(topic string, args ...interface{})

功能

发布一个指定主题的事件,并将参数传递给所有订阅该主题的回调函数。

应用场景

在程序中某个特定事件发生时,调用该函数通知所有订阅者。例如,在一个聊天应用中,当服务器收到新消息时,发布消息事件通知所有客户端。

示例代码

package mainimport ("fmt""github.com/asaskevich/EventBus"
)func calculator(a int, b int) {fmt.Printf("%d\n", a+b)
}func main() {bus := EventBus.New()err := bus.Subscribe("main:calculator", calculator)if err != nil {fmt.Printf("订阅事件 %s 失败: %v\n", "main:calculator", err)}bus.Publish("main:calculator", 20, 40) // 发布事件,传递参数 20 和 40
}

SubscribeAsync()

函数签名

func (bus *EventBus) SubscribeAsync(topic string, fn interface{}, transactional bool) error

功能

以异步方式订阅某个事件,transactional=true 时按顺序执行,false 时并发执行。

应用场景

用于后台异步处理任务,如写日志、发送邮件等不会阻塞主流程的任务。

返回错误

如果第二个参数传的不是函数,则会返回错误。

示例代码

package mainimport ("fmt""github.com/asaskevich/EventBus""time"
)func calculator(a int, b int) {time.Sleep(1 * time.Second)fmt.Printf("%d\n", a+b)
}func main() {bus := EventBus.New()err := bus.SubscribeAsync("main:calculator", calculator,false)if err != nil {fmt.Printf("异步处理事件 %s 失败: %v\n", "main:calculator", err)}bus.Publish("main:calculator", 20, 40)fmt.Println("Main continues...")bus.WaitAsync() // 等待所有异步回调完成
}

 SubscribeOnceAsync()

函数签名

func (bus *EventBus) SubscribeOnceAsync(topic string, fn interface{}, transactional bool) error

功能

以异步方式订阅事件,仅触发一次。

应用场景

用于一次性异步初始化、只执行一次的异步钩子或远程调用。

返回错误

如果第二个参数传的不是函数,则会返回错误。

示例代码

package mainimport ("fmt""github.com/asaskevich/EventBus""time"
)func calculator(a int, b int) {time.Sleep(1 * time.Second)fmt.Printf("%d\n", a+b)
}func main() {bus := EventBus.New()err := bus.SubscribeOnceAsync("main:calculator", calculator, false)if err != nil {fmt.Printf("一次性异步处理事件 %s 失败: %v\n", "main:calculator", err)}bus.Publish("main:calculator", 20, 40)bus.Publish("main:calculator", 20, 40) // 不会执行bus.WaitAsync()
}

 WaitAsync()

函数签名

func (bus *EventBus) WaitAsync()

功能

等待所有异步事件处理完成。

应用场景

在程序退出前等待所有异步任务结束,确保不会中断执行中的任务。

示例代码

package mainimport ("fmt""github.com/asaskevich/EventBus""time"
)func calculator(a int, b int) {time.Sleep(1 * time.Second)fmt.Printf("%d\n", a+b)
}func main() {bus := EventBus.New()err := bus.SubscribeAsync("main:calculator", calculator,false)if err != nil {fmt.Printf("异步处理事件 %s 失败: %v\n", "main:calculator", err)}bus.Publish("main:calculator", 20, 40)fmt.Println("Main continues...")bus.WaitAsync()
}

完整示例

package mainimport ("fmt""time""github.com/asaskevich/EventBus"
)func main() {// New()bus := EventBus.New()// Subscribe()bus.Subscribe("math:add", func(a int, b int) {fmt.Printf("Add: %d + %d = %d\n", a, b, a+b)})// SubscribeOnce()bus.SubscribeOnce("notify:once", func() {fmt.Println("This message will be shown only once.")})// HasCallback()if bus.HasCallback("math:add") {fmt.Println("Callback for 'math:add' exists.")}// Publish()bus.Publish("math:add", 10, 20)bus.Publish("notify:once")  // 第一次调用,有输出bus.Publish("notify:once")  // 第二次调用,无输出// Unsubscribe()printHello := func() { fmt.Println("Hello!") }bus.Subscribe("say:hello", printHello)bus.Publish("say:hello")bus.Unsubscribe("say:hello", printHello)bus.Publish("say:hello") // 已取消订阅,无输出// SubscribeAsync()bus.SubscribeAsync("async:greet", func(name string) {time.Sleep(1 * time.Second)fmt.Printf("Hello, %s (from async)\n", name)}, false)// SubscribeOnceAsync()bus.SubscribeOnceAsync("init:once", func() {time.Sleep(1 * time.Second)fmt.Println("Async init done (only once).")}, false)// 异步事件发布bus.Publish("async:greet", "Alice")bus.Publish("init:once")bus.Publish("init:once") // 第二次不会触发// WaitAsync()fmt.Println("Waiting for async handlers to finish...")bus.WaitAsync()fmt.Println("All async tasks completed.")
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/83182.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go语言接口:灵活多态的核心机制

引言 Go语言的接口系统是其​​面向对象编程​​的核心,它摒弃了传统语言的类继承体系,采用独特的​​隐式实现​​和​​鸭子类型​​设计。这种设计使得Go接口既灵活又强大,成为构建松耦合系统的关键工具。本文将深入剖析Go接口的实现机制…

DeviceNET转EtherCAT网关:医院药房自动化的智能升级神经中枢

在现代医院药房自动化系统中,高效、精准、可靠的设备通信是保障患者用药安全与效率的核心。当面临既有支持DeviceNET协议的传感器、执行器(如药盒状态传感器、机械臂限位开关)需接入先进EtherCAT高速实时网络时,JH-DVN-ECT疆鸿智能…

android实现使用RecyclerView详细

显示页面代码&#xff1a;activity_category_inventory.xml代码&#xff1a; <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android" xmlns:app"http://schemas.and…

【SpringBoot实战】优雅关闭服务

文章目录 一、什么是优雅关闭&#xff1f;二、优雅关闭的核心步骤三、SpringBoot优雅关闭实现四、关键注意事项1. 超时时间必须配置2. 信号支持局限性3. 特殊请求处理 五、底层实现原理六、总结 一、什么是优雅关闭&#xff1f; 优雅关闭&#xff08;Graceful Shutdown&#x…

C++哈希表:unordered系列容器详解

本节目标 1.unordered系列关联式容器 2.底层结构 3.模拟实现 4.哈希的应用 5.海量数据处理面试题 unordered系列关联式容器 在c98中&#xff0c;STL提供了底层为红黑树结构的一系列关联式容器&#xff0c;在查询时效率可以达到logN&#xff0c;即最差的情况下需要比较红…

java操作服务器文件(把解析过的文件迁移到历史文件夹地下)

第一步导出依赖 <dependency><groupId>org.apache.sshd</groupId><artifactId>sshd-core</artifactId><version>2.13.0</version></dependency> 第二步写代码 public void moveFile( List<HmAnalysisFiles> hmAnalys…

Oracle OCP认证的技术定位怎么样?

一、引言&#xff1a;Oracle OCP认证的技术定位​ Oracle Certified Professional&#xff08;OCP&#xff09;认证是数据库领域含金量最高的国际认证之一&#xff0c;其核心价值在于培养具备企业级数据库全生命周期管理能力的专业人才。随着数字化转型加速&#xff0c;OCP认证…

TK海外抢单源码/指定卡单

​ 抢单源码&#xff0c;有指定派单&#xff0c;打针&#xff0c;这套二改过充值跳转客服 前端vue 后端php 两端分离 可二开 可以指定卡第几单&#xff0c;金额多少&#xff0c; 前后端开源 PHP7.2 MySQL5.6 前端要www.域名&#xff0c;后端要admin.域名 前端直接静态 伪静…

远程线程注入

注入简单来说就是让别人的程序执行 你想要让他执行的dll #include<iostream> #include<Windows.h> using namespace std;char szBuffer[] "C:\\Users\\20622\\source\\repos\\Dll1\\Debug\\test.dll"; //dll路径void RemoteThreadInject(DWORD Pid,PCH…

【Java实战】集合排序方法与长度获取方法辨析(易懂版)

一、排序方法 1. 对List排序的两种方式 方式一Collections.sort() List<Integer> numbers Arrays.asList(3,1,4,2); Collections.sort(numbers); // 直接修改原list → [1,2,3,4]方式二&#xff1a;list.sort()&#xff08;Java8推荐&#xff09; List<String>…

企业级安全实践:SSL/TLS 加密与权限管理(一)

引言 ** 在数字化转型的浪潮中&#xff0c;企业对网络的依赖程度与日俱增&#xff0c;从日常办公到核心业务的开展&#xff0c;都离不开网络的支持。与此同时&#xff0c;网络安全问题也日益严峻&#xff0c;成为企业发展过程中不可忽视的重要挑战。 一旦企业遭遇网络安全事…

Java 大视界 -- Java 大数据在智能医疗影像数据压缩与传输优化中的技术应用(227)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

Python编程基础(一) | 变量和简单数据类型

引言&#xff1a;很久没有写 Python 了&#xff0c;有一点生疏。这是学习《Python 编程&#xff1a;从入门到实践&#xff08;第3版&#xff09;》的课后练习记录&#xff0c;主要目的是快速回顾基础知识。 练习1&#xff1a; 简单消息 将一条消息赋给变量&#xff0c;并将其…

鸿蒙 HarmonyOS - SideBarContainer 组件自学指南

在日常开发中&#xff0c;如果你有类似「左侧导航 右侧内容」的布局需求&#xff0c;比如后台管理界面、文件管理器、设置页等&#xff0c;​​SideBarContainer​​ 是非常值得掌握的组件。它自带侧边栏和主内容区的分离机制&#xff0c;还支持折叠、拖拽、控制按钮和多种显示…

CppCon 2014 学习:Practical Functional Programming

这段内容是对**在 C 中使用函数式编程&#xff08;Functional Programming, FP&#xff09;**可以做什么的简要介绍&#xff0c;下面是逐条的翻译与理解&#xff1a; Introduction 简介 在 C 中使用函数式编程&#xff08;FP&#xff09;可以做什么&#xff1f; 1. 编写强大…

飞牛NAS+Docker技术搭建个人博客站:公网远程部署实战指南

文章目录 前言1. Docker下载源设置2. Docker下载WordPress3. Docker部署Mysql数据库4. WordPress 参数设置5. 飞牛云安装Cpolar工具6. 固定Cpolar公网地址7. 修改WordPress配置文件8. 公网域名访问WordPress总结 前言 在数字化浪潮中&#xff0c;传统网站搭建方式正面临前所未…

ComfyUI+阿里Wan2.1+内网穿透技术:本地AI视频生成系统搭建实战

文章目录 前言1.软件准备1.1 ComfyUI1.2 文本编码器1.3 VAE1.4 视频生成模型 2.整合配置3. 本地运行测试4. 公网使用Wan2.1模型生成视频4.1 创建远程连接公网地址 5. 固定远程访问公网地址总结 前言 各位技术爱好者&#xff0c;今天为您带来一组创新性的AI应用方案&#xff01…

n8n:技术团队的智能工作流自动化助手

在当前数字化时代,自动化已经成为提高效率和减轻人工工作负担的一大推动力。今天,我们要为大家介绍一款极具潜力的开源项目——n8n,它不仅拥有广泛的应用场景,还具备内置AI功能,能够完全满足技术团队的高效工作需求。n8n的出现,为技术团队提供了自由编程与快速自动化构建…

1,QT的编译教程

目录 整体流程: 1,新建project文件 2,编写源代码 3,打开QT的命令行窗口 4,生成工程文件(QT_demo.pro) 5,生成Make file 6,编译工程 7,运行编译好的可执行文件 整体流程: 1,新建project文件 新建文本文件,后缀改为.cpp 2,编写源代码

深度学习论文: FastVLM: Efficient Vision Encoding for Vision Language Models

深度学习论文: FastVLM: Efficient Vision Encoding for Vision Language Models FastVLM: Efficient Vision Encoding for Vision Language Models PDF: https://www.arxiv.org/abs/2412.13303 PyTorch代码: https://github.com/shanglianlm0525/CvPytorch PyTorch代码: https…