回到目錄 讓大叔興奮的自動化註冊 對於領域事件之前說過,在程式啟動時訂閱(註冊)一些事件處理程式,然後在程式的具體位置去發佈(觸發)它,這是傳統的pub/sub模式的體現,當然也沒有什麼問題,為了讓它支持分散式的場景,我們引用了redis這種存儲介質,這一切都早已集成到了Lind.DDD架構中,對些 ...
讓大叔興奮的自動化註冊
對於領域事件之前說過,在程式啟動時訂閱(註冊)一些事件處理程式,然後在程式的具體位置去發佈(觸發)它,這是傳統的pub/sub模式的體現,當然也沒有什麼問題,為了讓它支持分散式的場景,我們引用了redis這種存儲介質,這一切都早已集成到了Lind.DDD架構中,對些沒什麼好說的,而今天的重點在於"事件的自動過註冊"的理念,這個概念真實在ABP架構中出現了,大叔覺得很不錯,所以也集成到了自己的架構中,為些也興奮了一段時間,其中有解決問題的
Redis只是一種分散式存儲介質
對於第一版將事件匯流排放到記憶體的情況來說,使用redis這種存儲介質確實解決了分散式的事件問題,它可以在更多場合下使用,不用考慮WEB端的負載均衡,不用考慮服務端的存儲壓力,不用考慮併發時的吞吐量,確實,redis是個存儲效率非常高的產物,大叔redis里的事件的Key採用了當前EventData的名字加上自定義的首碼,這樣可以同時在多個項目中使用.
/// <summary> /// 對於事件數據的存儲,目前採用記憶體字典 /// </summary> private readonly IRedisClient _redisClient = RedisManager.GetClient(); /// <summary> /// redis事件匯流排的Key /// </summary> private string redisKey = ConfigConstants.ConfigManager.Config.DomainEvent.RedisKey; /// <summary> /// 得到當前redis-eventbus-key /// </summary> /// <typeparam name="TEvent"></typeparam> /// <returns></returns> private string GetCurrentRedisKey<TEvent>() { return redisKey + "_" + typeof(TEvent).FullName; } /// <summary> ///得到非泛型版本的值 /// </summary> /// <param name="tEvent"></param> /// <returns></returns> private string GetCurrentRedisKey(Type tEvent) { return redisKey + "_" + tEvent.FullName; }
結構圖
主角是SubscribeAll這個方法
對於當前應用程式下的所有DLL進行反射,拿到所有實現了IEventHandler的類型,然後對這麼類型(事件處理程式)進行註冊即可.
核心代碼(Memory版):
/// <summary> /// 需要過濾的介面 /// </summary> string[] Excepts = { "IEventHandler`1", "ActionDelegatedEventHandler`1" }; /// <summary> /// 全局統一註冊所有事件處理程式,實現了IEventHandlers的 /// </summary> public void SubscribeAll() { var types = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(a => a.GetTypes() .Where(t => t.GetInterfaces().Contains(typeof(IEventHandlers)))) .Where(i => !Excepts.Contains(i.Name)) .ToArray(); foreach (var item in types) { if (!item.ContainsGenericParameters) { var en = Activator.CreateInstance(item); foreach (var t in item.GetInterfaces().Where(i => i.Name != "IEventHandlers")) { Subscribe(t, en); } } } } /// <summary> /// 訂閱非泛型版 /// </summary> /// <param name="type"></param> /// <param name="eventHandler"></param> void Subscribe(Type type, object eventHandler) { lock (_objLock) { var eventType = type.GetGenericArguments()[0]; //var eventType = type.GetType().GenericTypeArguments[0]; if (_eventHandlers.ContainsKey(eventType)) { var handlers = _eventHandlers[eventType]; if (handlers != null) { if (!handlers.Exists(deh => _eventHandlerEquals(deh, eventHandler))) handlers.Add(eventHandler); } else { handlers = new List<object>(); handlers.Add(eventHandler); } } else _eventHandlers.Add(eventType, new List<object> { eventHandler }); } }
對於這種倉儲,在Redis里事實上是以二進位的格式存儲的,所以要求你的EventData和EventHandler需要標記為可序列化,我經過測試,對於Json序列化的方式,在進行發佈時,不能成功回調"訂閱"的代碼,原因我目前還不清楚,需要大家一起去研究!
感謝各位的閱讀!