Badu/bus:Go 轻量级泛型发布/订阅事件总线

badu/bus (github.com/badu/bus) 是一个 Go 语言基于泛型实现的轻量级发布-订阅(Pub/Sub)事件总线库。它允许不同的组件通过事件机制进行解耦通信,而不需要直接调用彼此的函数。

它解决了什么问题?

  • 组件解耦:发布者和订阅者彼此无感知,更灵活、可扩展,便于测试。
  • 异步消息:消息可以异步发送和接收,提高系统性能和响应速度。
  • 模块化:有利于将系统拆分为更小、可维护的模块。

安装

arduino 复制代码
go get github.com/badu/bus

示例

我们构建一个解耦的订单系统,它的业务逻辑包括:

  • 订单创建(order 模块)
  • 通知用户(notification 模块)
  • 记录日志(logging 模块)
  • 自动发货(shipping 模块)

当用户下单时:订单系统只负责发布事件,不会直接调用通知、日志、发货等模块。其他模块独立监听事件,执行自己的逻辑。

项目结构

perl 复制代码
📦 order-system
├── 📂 events           # 事件模块
│   ├── events.go       # 事件
├── 📂 order            # 订单模块
│   ├── order.go        # 订单创建
├── 📂 notification     # 通知模块
│   ├── notify.go       # 发送通知
├── 📂 logging          # 日志模块
│   ├── log.go          # 记录日志
├── 📂 shipping         # 物流模块
│   ├── ship.go         # 自动发货
├── main.go             # 启动程序

事件(events/events.go)

首先,始终将事件放在单独的 events 包中,避免循环依赖。所有模块都会使用它:

go 复制代码
package events

// OrderEvent 订单事件
type OrderEvent struct {
 ID string
}

订单模块(order/order.go)

订单模块负责创建订单并发布事件,但不关心其他模块如何处理订单。

go 复制代码
package order

import (
 "fmt"
 "github.com/badu/bus"
 "order-system/events"
)

// PlaceOrder 下单函数
func PlaceOrder(orderID string) {
 fmt.Println("🛒 订单已创建:", orderID)

 // 订单创建后,发布 "OrderEvent" 事件
 bus.Pub(events.OrderEvent{ID: orderID})
}

通知模块(notification/notify.go)

监听订单事件,发送通知。

go 复制代码
package notification

import (
 "fmt"
 "github.com/badu/bus"
 "order-system/events"
)

// NotifyUser 发送通知
func NotifyUser(event events.OrderEvent) {
 fmt.Println("📢 通知用户: 订单", event.ID, "已创建")
}

// Init 初始化时订阅事件
func Init() {
 bus.Sub(NotifyUser)
}

日志模块(logging/log.go)

监听订单事件,记录日志。

go 复制代码
package logging

import (
 "fmt"
 "github.com/badu/bus"
 "order-system/events"
)

// LogOrder 记录订单日志
func LogOrder(event events.OrderEvent) {
 fmt.Println("📝 记录日志: 订单", event.ID, "已创建")
}

// Init 初始化时订阅事件
func Init() {
 bus.Sub(LogOrder)
}

物流模块(shipping/ship.go)

监听订单事件,自动发货。

go 复制代码
package shipping

import (
 "fmt"
 "github.com/badu/bus"
 "order-system/events"
)

// AutoShip 处理自动发货
func AutoShip(event events.OrderEvent) {
 fmt.Println("🚚 订单", event.ID, "已进入发货流程")
}

// Init 初始化时订阅事件
func Init() {
 bus.Sub(AutoShip)
}

主函数(main.go)

在 main.go 中,我们初始化所有订阅者,触发订单创建。

go 复制代码
package main

import (
 "order-system/logging"
 "order-system/notification"
 "order-system/order"
 "order-system/shipping"
)

func main() {
 // 初始化事件订阅
 notification.Init()
 logging.Init()
 shipping.Init()

 // 用户下单
 order.PlaceOrder("12345")
}

运行结果

复制代码
🛒 订单已创建: 12345
📢 通知用户: 订单 12345 已创建
📝 记录日志: 订单 12345 已创建
🚚 订单 12345 已进入发货流程

order 模块只负责订单逻辑,而 notification、logging、shipping 模块各自监听事件,独立执行逻辑。

常见问题

示例

go 复制代码
// InterestingEvent 定义事件
type InterestingEvent struct {
}

// OnMyEventOccurred 处理函数
func OnMyEventOccurred(event InterestingEvent) {
 // do something with the event here
}


bus.Sub(OnMyEventOccurred) // 订阅

bus.Pub(InterestingEvent{}) // 发布

如何取消订阅:

css 复制代码
 subscription := bus.Sub(OnMyEventOccurred)
 // 需要时调用 cancel,OnMyEventOccurred 函数将不再被调用
 subscription.Cancel()

只订阅一次:

csharp 复制代码
// OnMyEventOccurred 处理函数
func OnMyEventOccurred(event InterestingEvent) bool {
 // do something with the event here
 return true // 事件处理器需返回 true
}

bus.SubCancel(OnMyEventOccurred) // 订阅

异步处理事件:

less 复制代码
 bus.PubAsync(InterestingEvent{}) // 发布

查看已注册的事件:

go 复制代码
 bus.Range(func(k, v any) bool {
  fmt.Printf("%#v %#v\n", k, v)
  return true
 })

References

github.com/badu/bus

相关推荐
闪学it17 分钟前
Python测试开发进阶线上班28期
后端
Go_error20 分钟前
Go-redis:执行 Lua 脚本
后端·go
IT毕设实战小研44 分钟前
电影数据可视化推荐系统
大数据·后端·爬虫·python·算法·信息可视化·课程设计
ssshooter1 小时前
AI 时代你不能不知道的 git worktree
前端·后端·面试
Cosolar1 小时前
一文弄懂 Agent Harness 与 Agent Runtime 的区别
java·后端·github
长大19882 小时前
Python代码慢?这5个性能优化技巧让速度提升100倍
后端
超超不吵吵2 小时前
Java AI转型实战(十):Agent 智能体初探
后端
步行cgn2 小时前
@AllArgsConstructor 是 Lombok 提供的注解
后端
柠檬味拥抱2 小时前
鸿蒙原生 AI 应用开发实战:用蓝耘 MaaS 给纪念日 App 装上「大模型大脑」
后端