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