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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM