本文介绍了事件总线实现。

Grafana

源码文件地址:grafana/bus.go at main · grafana/grafana · GitHub

1.注册和调用

在这个项目里面随处可见这种写法:

Golang事件系统Event Bus

bus.Dispatch(&query)GetAlertByIdQuery

Golang事件系统Event Bus

Alert
GetAlertById

Golang事件系统Event Bus

问题来了,这是怎么实现的呢?Dispatch到底做了哪些操作?这样做有什么好处?

下面我来一一解答:

AddHandler

Golang事件系统Event Bus

其实这个方法的逻辑也很简单,所谓注册也就是把通过一个map把函数名和对应的函数做一个映射关系保存起来,当我们Dispatch的时候其实就是通过参数名查找之前注册过的函数,然后通过反射调用该函数。

Bus结构体里面有几个map成员,在这个项目里面作者定义了3种不同类型的handler,一种是普通的handler,也就是刚才展示的那种,第二种是带上下文的handler,还有一种则是事件订阅用到的handler,我们给一个事件注册多个监听者,当事件触发的时候会依次调用多个监听函数,其实就是一个观察者模式。

Golang事件系统Event Bus

AddHandler

Golang事件系统Event Bus

Dispatch方法的源码如下:

Golang事件系统Event Bus
AddHandlerCtxDispatchCtx

2.订阅和发布

AddEventListenerPublish

Golang事件系统Event Bus

查看源码可以得知,可以给一个事件注册多个handler函数,而Publish的时候则是依次调用注册的函数,逻辑也不复杂。

Golang事件系统Event Bus

这里面有一点不好,所有订阅函数的调用是顺序的,并没有使用协程,所以如果注册了很多个函数,这样效率也不高啊。

3.好处

可能有人会好奇,为什么明明可以直接调用函数就行,为啥非得绕个弯子,整这么复杂?

况且,每次调用都得使用反射机制,性能也不行。

我觉得主要有以下几点:

1.这种写法逻辑清晰,解耦

2.方便单元测试

3.性能不是最大考量,虽然说反射会降低性能

转自:wangbjun.site/2021/coding/golang/event-bus.html