DDD事件总线的实现
基本思路:
(1) 在事件总线内部维护着一个事件与事件处理程序相映射的字典。
(2) 利用反射,事件总线会将实现了IEventHandler的处理程序与相应事件关联到一起,相当于实现了事件处理程序对事件的订阅。
(3) 当发布事件时,事件总线会从字典中找出相应的事件处理程序,然后利用反射去调用事件处理程序中的方法。
核心类(事件总线类)
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 }
核心类(事件处理程序接口)
1 namespace Framework.EventBus 2 { 3 public interface IEventHandler<T> 4 where T : BaseEvent 5 { 6 void Handle(T eventData); 7 } 8 }
使用方法
实现接口IEventHandler<T>
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事件
订单类
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