一、前言
事件是基於委托的發布-訂閱機制(基於windows消息處理機制)通過定義事件,訂閱事件、發布事件並且關聯業務邏輯,實現系統業務的解耦。發布-訂閱機制提供了一種天然的業務解耦方式,所以在系統中使用事件定義業務狀態、業務場景,讓關聯的業務訂閱事件,當事件產生時事件訂閱者執行業務,這樣發布者不必知道訂閱者具體的細節、訂閱者也不必了解發布者。但是簡單的事件無法滿足實際生產的使用,因為生產中的業務是復雜的,多樣的,所以就要設計一種框架來統一管理事件設計成事件總線。
二、設計
事件總線進行抽象成如下接口關系圖,IEventBus作為事件總線進行協調管理事件的發布訂閱,作為事件中心承擔的職責除了事件的發布和訂閱之外,還包括對事件存儲、容錯、路由、異步、重試等。
事件總線類說明 | |
IEvent | 事件載體的接口,所有事件繼承該接口,定義一個事件,並且賦予事件相應的業務邏輯,比如這個事件要產生的業務操作 |
IEventHandler | 事件處理接口,每一個事件都必須關聯相應的事件操作 |
IEventSubscriber | 發布訂閱機制的訂閱事件接口,主要功能訂閱事件關聯事件處理器 |
IEventPublisher | 發布訂閱機制的發布事件接口,主要功能對產生的事件進行發布 |
IEventBus | 事件總線接口,通過聚合事件的發布和訂閱接口,在內部抽象成一個總線的方式統一管理事件,並且引入事件消息存儲結構 |
三、代碼
依據上述的事件總線接口關系圖,在代碼上定義各接口類,然后定義接口的關系創建一個初步的事件總線,通過事件總線接口來實現具體事件總線框架。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace TQF.EventBus.EventFramwork { /// <summary> /// 事件消息接口,定義一個事件,事件載體 /// </summary> public interface IEvent { /// <summary> /// 事件Id /// </summary> Guid EventId { get; } /// <summary> /// 事件時間 /// </summary> DateTime EventDate { get; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace TQF.EventBus.EventFramwork { /// <summary> /// 事件處理接口,定義一個事件對應的處理邏輯 /// </summary> public interface IEventHandler { /// <summary> /// 定義事件異步的處理器 /// </summary> /// <param name="event">使用@區分關鍵字</param> /// <param name="cancellationToken">任務取消令牌,取消任務</param> /// <returns></returns> Task<bool> HandlerAsync(IEvent @event, CancellationToken cancellationToken = default); bool CanHandle(IEvent @event); } /// <summary> /// 泛型事件處理器 /// </summary> /// <typeparam name="T"></typeparam> public interface IEventHandler<in T> : IEventHandler where T : IEvent { Task<bool> HandleAsync(T @event, CancellationToken cancellationToken = default); } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace TQF.EventBus.EventFramwork { /// <summary> /// 事件發布器,發布消息 /// </summary> public interface IEventPublisher:IDisposable { /// <summary> /// 事件發布器,發布事件 /// </summary> /// <typeparam name="TEvent"></typeparam> /// <param name="event">事件</param> /// <param name="cancellationToken">任務取消令牌,取消任務</param> /// <returns></returns> Task PublishAsync<TEvent>(TEvent @event, CancellationToken cancellationToken = default) where TEvent : IEvent; } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace TQF.EventBus.EventFramwork { /// <summary> /// 事件訂閱器訂閱消息 /// </summary> public interface IEventSubscriber:IDisposable { void Subscriber(); } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace TQF.EventBus.EventFramwork { /// <summary> /// 事件總線接口,定義事件通訊渠道,消息訂閱功能,消息派發功能(消息的路由,過濾,選擇)等。 /// 通過事件總線管理兩者 /// </summary> public interface IEventBus:IEventPublisher,IEventSubscriber { } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace TQF.EventBus.EventFramwork { /// <summary> /// 定義事件傳遞的參數 /// </summary> public class EventProcessedEventArgs:EventArgs { public IEvent Event { get; } public EventProcessedEventArgs(IEvent @event) { this.Event = @event; } } }
四、總結
1、事件總線的目的是對業務的解耦,通過設計合理的架構來達到這個目標,既然是合理的框架,就涉及到存儲、容錯、路由、異步、重試等問題,所以上述提供是一個事件總線雛形。
2、對於模式和架構,一個模式,一個架構其構成的最小單位可以理解為對象,通過對對象的划分、割裂,單獨成個體,通過關系連接這些個體,建立起一個模型->模式->架構。