经过几天的努力拜读大牛高手文章,终于对事件总线有所了解,特此记录下来,以免忘记
1、定义相关的接口:
A 事件接口
1 public interface IDomainEvent 2 { 3 DateTime OccurredOn(); 4 5 /// <summary> 6 /// 设置为已读 7 /// </summary> 8 /// <returns></returns> 9 void Read(); 10 11 /// <summary> 12 /// 是否已读 13 /// </summary> 14 bool IsRead { get; } 15 }
B 事件订阅接口
public interface IDomainEventSubscriber{Type SubscribedToEventType();void Handle(object domainEvent);}
2、定义相关实现
A 事件实现
public abstract class DomainEvent : IDomainEvent{public readonly DateTime OccurredOnTime;public string ID;protected DomainEvent(){this.ID = Guid.NewGuid().ToString();this.OccurredOnTime = DateTime.Now;this.IsRead = false;}public DateTime OccurredOn(){return this.OccurredOnTime;}public void Read(){this.IsRead = true;}public bool IsRead { get; private set; }}
B 事件订阅实现
public abstract class DomainEventSubscriber<T> : IDomainEventSubscriber where T : IDomainEvent{/// <summary>订阅的事件类型/// </summary>/// <returns></returns>public Type SubscribedToEventType(){return typeof(T);}public abstract void HandleEvent(T domainEvent);public void Handle(object domainEvent){if (domainEvent is T){this.HandleEvent((T)domainEvent);}else{throw new NotSupportedException(string.Format("当前订阅者支持的事件类型是:{0},当前事件是:{1}", typeof(T).FullName, domainEvent.GetType().FullName));}}}
3、定义事件总线实现
public class DomainEventBus{public delegate void DistributeExceptionHandle(IDomainEventSubscriber subscriber, IDomainEvent domainEvent, Exception exception);/// <summary>/// Key:DomainEvent的类型,Value订阅该类型事件的订阅者列表/// </summary>private static readonly Dictionary<Type, List<IDomainEventSubscriber>> _subscribers = new Dictionary<Type, List<IDomainEventSubscriber>>();private static readonly object _lockObj = new object();public event DistributeExceptionHandle DistributeExceptionEvent;private static DomainEventBus _instance;public static DomainEventBus Instance(){if (_instance != null)return _instance;var temp = new DomainEventBus();Interlocked.CompareExchange(ref _instance, temp, null);return temp;}public void Publish<T>(T aDomainEvent) where T : IDomainEvent{if (aDomainEvent.IsRead)return;var registeredSubscribers = _subscribers;if (registeredSubscribers != null){var domainEventType = aDomainEvent.GetType();List<IDomainEventSubscriber> subscribers;if (!registeredSubscribers.TryGetValue(domainEventType, out subscribers)){aDomainEvent.Read(); //未找到订阅者,但是消息还是消费掉。return;}foreach (var domainEventSubscriber in subscribers){var subscribedTo = domainEventSubscriber.SubscribedToEventType();if (subscribedTo == domainEventType || subscribedTo is IDomainEvent){Distribute(domainEventSubscriber, aDomainEvent);}}aDomainEvent.Read();}}private void Distribute(IDomainEventSubscriber subscriber, IDomainEvent domainEvent){try{subscriber.Handle(domainEvent);}catch (Exception ex){OnDistributeExceptionEvent(subscriber, domainEvent, ex);}}public void Subscribe(IDomainEventSubscriber aSubscriber){lock (_lockObj){var registeredSubscribers = _subscribers;var domainEventType = aSubscriber.SubscribedToEventType();List<IDomainEventSubscriber> subscribers;if (!registeredSubscribers.TryGetValue(domainEventType, out subscribers)){subscribers = new List<IDomainEventSubscriber>();registeredSubscribers.Add(domainEventType, subscribers);}if (subscribers.Any(ent => ent.SubscribedToEventType().FullName == aSubscriber.SubscribedToEventType().FullName && ent.GetType().FullName == aSubscriber.GetType().FullName)) //相同的订阅只接收一次。return;subscribers.Add(aSubscriber);}}protected virtual void OnDistributeExceptionEvent(IDomainEventSubscriber subscriber, IDomainEvent domainEvent, Exception exception){var handler = DistributeExceptionEvent;if (handler != null)handler(subscriber, domainEvent, exception);}}
4、定义具体的事件
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
public class OrderCreated : DomainEventCore.DomainEvent{public string OrderId { get; private set; }public string UserId { get; private set; }public string Receiver { get; private set; }public OrderCreated(string orderId, string userId, string receiver){this.OrderId = orderId;this.UserId = userId;this.Receiver = receiver;}}
5、定义具体事件触发后要执行的方法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
public class OrderCreatedSubscriberPaymentContext : DomainEventSubscriber<OrderCreated>{public override void HandleEvent(OrderCreated domainEvent){//TODO anythingConsole.WriteLine("Order ID:{0},i have payment",domainEvent.OrderId);}}
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
public class OrderCreatedSubscriberSellingPriceContext : DomainEventSubscriber<OrderCreated>{public override void HandleEvent(OrderCreated domainEvent){//TODO anythingConsole.WriteLine("Order ID:{0},i have show price", domainEvent.OrderId);}}
6、代码测试
class Program{static void Main(string[] args){//事件订阅DomainEventBus.Instance().Subscribe(new OrderCreatedSubscriberSellingPriceContext());DomainEventBus.Instance().Subscribe(new OrderCreatedSubscriberPaymentContext());var tempGuid = Guid.NewGuid().ToString();var entity = new OrderCreated(tempGuid, "mikechang", "sprite");Console.WriteLine("生产一个新的订单:{0}",tempGuid);//事件发布 DomainEventBus.Instance().Publish(entity);Console.ReadLine();}}