標籤:actor 方法 bsp reg 升級 服務 伺服器 自己 eal
回到目錄
理論閑話
之前在.netFramework平台用的好好的,可升級到.net core平台之後,由於不再需要二進位序列化,導致咱們的事件機制遇到了問題,之前大叔的事件一直是將處理常式序列化後進行儲存的,處理儲存的參數為事件來源,一個事件來源可以由多個處理常式訂閱,當事件來源被發布時,這些被序列化的程式碼片段會被回調執行,這是大叔之前的思路,在RedisBus和MemoryBus裡已經得到了實現,讀過大叔原始碼的同學應該有所瞭解了。
事件來源和處理常式
/// <summary> /// 事件來源 /// </summary> public class CreateUserCommand : BusData { public string UserName { get; set; } } /// <summary> /// 事件處理常式 /// </summary> public class CreateUserCommandHandler : IBusHandler<CreateUserCommand> { public void Handle(CreateUserCommand evt) { LoggerFactory.CreateLog().Logger_Debug(evt.UserName); Console.WriteLine("CreateUserCommandHandler"); } }
關於服務匯流排的實現方式
- RedisBus基於redis進行儲存,事件發布後,所有相關處理常式被回調,要求事件和處理常式是可序列化的
- MemoryBus基於應用伺服器緩衝進行儲存,所有相關處理常式被回調,叢集環境不是很適合
- IoCBus基於redis作為事件字典,處理常式由IoC容器進行注入,使用場合更廣
IoCBus實現思想與組成
- 應該有一個儲存事件與處理常式對應關係的字典
- 字典應該被持久化到中介軟體裡
- 應該有個容器,去管理字典值與處理常式的關係
代碼實現
資料變更的定義
/// <summary> /// redis key /// </summary> const string ESBKEY = "IoCESBBus"; /// <summary> /// redis事件字典 /// </summary> IDatabase redis = RedisManager.Instance.GetDatabase(); /// <summary> /// 模式鎖 /// </summary> private static object _objLock = new object(); /// <summary> /// 對於事件數目據的儲存,目前採用記憶體字典 /// </summary> private readonly IContainer container = new AutofacContainer();
事件的統一訂閱
public void SubscribeAll() { var types = AssemblyHelper.GetTypesByInterfaces(typeof(IBusHandler<>)); Dictionary<string, List<string>> keyDic = new Dictionary<string, List<string>>(); foreach (var item in types) { if (!item.IsGenericParameter) { TypeInfo typeInfo = IntrospectionExtensions.GetTypeInfo(item); foreach (var t in typeInfo.GetMethods().Where(i => i.Name == "Handle")) { //ioc name key var eventKey = t.GetParameters().First().ParameterType.Name; var key = t.GetParameters().First().ParameterType.Name + "_" + item.Name; //eventhandler var inter = typeof(IBusHandler<>).MakeGenericType(t.GetParameters().First().ParameterType); container.Register(inter, item, key); if (keyDic.ContainsKey(eventKey)) { var oldEvent = keyDic[eventKey]; oldEvent.Add(key); } else { var newEvent = new List<string>(); newEvent.Add(key); keyDic.Add(eventKey, newEvent); } } } //redis儲存事件與處理常式的映射關係 foreach (var hash in keyDic) redis.HashSet( ESBKEY, hash.Key.ToString(), JsonConvert.SerializeObject(hash.Value)); } }
事件的發布,相關處理常式會從容器中取出,並執行它們的Handler方法
public void Publish<TEvent>(TEvent @event) where TEvent : class, IBusData { var keyArr = JsonConvert.DeserializeObject<List<string>>(redis.HashGet(ESBKEY, typeof(TEvent).Name)); foreach (var key in keyArr) { var item = container.ResolveNamed<IBusHandler<TEvent>>(key); item.Handle(@event); } }
說到這裡,大叔的服務匯流排的IoC實現方式就算是完成了,經過測試後,在.net core上表現也很不錯!
自己也驕傲一次,呵呵!
回到目錄
DotNetCore跨平台~服務匯流排_事件匯流排的重新設計