基本思路:html
(1) 在事件總線內部維護着一個事件與事件處理程序相映射的字典。git
(2) 利用反射,事件總線會將實現了IEventHandler的處理程序與相應事件關聯到一塊兒,至關於實現了事件處理程序對事件的訂閱。github
(3) 當發佈事件時,事件總線會從字典中找出相應的事件處理程序,而後利用反射去調用事件處理程序中的方法。app
核心類(事件總線類)框架
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Reflection; 5 6 7 namespace Framework.EventBus 8 { 9 public class EventBus 10 { 11 12 private static EventBus _eventBus = null; 13 14 private static Dictionary<Type, List<Type>> _eventMapping = new Dictionary<Type, List<Type>>(); // 在這個字典中,key存儲的是事件,而value中存儲的是事件處理程序 15 16 17 private EventBus() { } 18 /// <summary> 19 /// 單例 20 /// </summary> 21 /// <returns></returns> 22 public static EventBus Instance() 23 { 24 if (_eventBus == null) 25 { 26 _eventBus = new EventBus(); 27 MapEvent2Handler(); 28 } 29 return _eventBus; 30 } 31 32 33 34 /// <summary> 35 /// 發佈 36 /// 這裏沒有用到隊列之類的東西,使用的是直接調用的方式 37 /// </summary> 38 /// <param name="eventData"></param> 39 public void Publish(BaseEvent eventData) 40 { 41 // 找出這個事件對應的處理者 42 Type eventType = eventData.GetType(); 43 44 if (_eventMapping.ContainsKey(eventType) == true) 45 { 46 foreach (Type item in _eventMapping[eventType]) 47 { 48 MethodInfo mi = item.GetMethod("Handle"); 49 if (mi != null) 50 { 51 object o = Activator.CreateInstance(item); 52 mi.Invoke(o, new object[] { eventData }); 53 } 54 } 55 56 } 57 } 58 59 60 61 62 63 /// <summary> 64 /// 將事件與事件處理程序映射到一塊兒 65 /// 使用元數據來進行註冊 66 /// </summary> 67 static void MapEvent2Handler() 68 { 69 Assembly assembly = Assembly.GetExecutingAssembly(); 70 Type[] types = assembly.GetTypes(); 71 72 foreach (Type type in types) 73 { 74 Type handlerInterfaceType = type.GetInterface("IEventHandler`1"); // 事件處理者 75 76 if (handlerInterfaceType != null) // 如果事件處理者,則以其泛型參數爲key,事件處理者的集合爲value添加到映射中 77 { 78 Type eventType = handlerInterfaceType.GetGenericArguments()[0]; // 這裏只有一個 79 // 查找是否存在key 80 if (_eventMapping.Keys.Contains(eventType)) 81 { 82 List<Type> handlerTypes = _eventMapping[eventType]; 83 handlerTypes.Add(type); 84 _eventMapping[eventType] = handlerTypes; 85 } 86 else // 存在則添加 87 { 88 List<Type> handlerTypes = new List<Type>(); 89 handlerTypes.Add(type); 90 _eventMapping.Add(eventType, handlerTypes); 91 } 92 } 93 } 94 } 95 96 } 97 }
核心類(事件基類)分佈式
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace Framework.EventBus 7 { 8 public class BaseEvent 9 { 10 11 /// <summary> 12 /// 事件發生的時間 13 /// </summary> 14 public DateTime EventTime { get; set; } 15 16 /// <summary> 17 /// 事件源 18 /// </summary> 19 public object EventSource { get; set; } 20 21 22 } 23 }
核心類(事件處理程序接口)spa
1 namespace Framework.EventBus 2 { 3 public interface IEventHandler<T> 4 where T : BaseEvent 5 { 6 void Handle(T eventData); 7 } 8 }
使用方法設計
實現接口IEventHandler<T>code
1 using System; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 7 8 namespace Framework.EventBus 9 { 10 /// <summary> 11 /// 實現了IEventHandler<OrderAddedEvent>接口,就是訂閱了OrderAddedEvent事件 12 /// </summary> 13 public class OrderAddedEventHandler1 : IEventHandler<OrderAddedEvent> 14 { 15 public void Handle(OrderAddedEvent eventData) 16 { 17 18 Console.WriteLine("\r\n"); 19 Console.WriteLine("訂單的數據是:" ); 20 Console.WriteLine(" 訂單號:" + eventData.Order.OrderId); 21 Console.WriteLine(" 訂單金額:" + eventData.Order.OrderAmount); 22 Console.WriteLine(" 下單時間:" + eventData.Order.OrderDateTime); 23 24 } 25 } 26 }
注:實現了IEventHandler<OrderAddedEvent>接口,就是訂閱了OrderAddedEvent事件htm
訂單類
1 public class OrderEntity 2 { 3 4 /// <summary> 5 /// 訂單編號 6 /// </summary> 7 public string OrderId { get; set; } 8 9 10 /// <summary> 11 /// 下單日期 12 /// </summary> 13 public DateTime OrderDateTime { get; set; } 14 15 16 /// <summary> 17 /// 訂單金額 18 /// </summary> 19 public decimal OrderAmount { get; set; } 20 21 }
發佈事件
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 7 namespace Framework.EventBus 8 { 9 class Program 10 { 11 static void Main(string[] args) 12 { 13 EventBus bus = EventBus.Instance(); 14 15 OrderEntity order = new OrderEntity() { OrderId = "20151017001", OrderDateTime = DateTime.Now, OrderAmount = 500 }; 16 bus.Publish(new OrderAddedEvent() { EventTime = DateTime.Now, Order = order }); // 發佈OrderAddedEvent事件, 17 19 Console.Read(); 20 } 21 22 } 23 }
運行結果
改進
(1)實現基於msmq的事件總線,使得系統可以進行分佈式的事件訂閱和發佈。
下載
參考資料
aspnetboilerplate
https://github.com/aspnetboilerplate/aspnetboilerplate
分享一個分佈式消息總線,基於.NET Socket Tcp的發佈-訂閱框架
http://www.cxyclub.cn/n/53667/
Guava - EventBus(事件總線)
http://greengerong.com/blog/2014/11/27/guava-eventbus/
DDD~領域事件與事件總線
http://www.cnblogs.com/lori/p/3476703.html
事件總線 EventBus的設計
http://www.cnblogs.com/MartinChen999/archive/2011/12/21/2294034.html