宝塔没有域名直接做网站怎么弄,wordpress 黑客主题,搜索引擎优化有哪些,wordpress模板脚步代码哪里修改动手造轮子#xff1a;实现一个简单的 EventBusIntroEventBus 是一种事件发布订阅模式#xff0c;通过 EventBus 我们可以很方便的实现解耦#xff0c;将事件的发起和事件的处理的很好的分隔开来#xff0c;很好的实现解耦。微软官方的示例项目 EShopOnContainers 也有在使… 动手造轮子实现一个简单的 EventBusIntroEventBus 是一种事件发布订阅模式通过 EventBus 我们可以很方便的实现解耦将事件的发起和事件的处理的很好的分隔开来很好的实现解耦。微软官方的示例项目 EShopOnContainers 也有在使用 EventBus 。这里的 EventBus 实现也是参考借鉴了微软 eShopOnContainers 项目。EventBus 处理流程微服务间使用 EventBus 实现系统间解耦借助 EventBus 我们可以很好的实现组件之间服务之间系统之间的解耦以及相互通信的问题。起初觉得 EventBus 和 MQ 其实差不多嘛都是通过异步处理来实现解耦合高性能。后来看到了下面这张图才算明白为什么要用 EventBus 以及 EventBus 和 MQ 之间的关系EventBus 是抽象的可以用 MQ 来实现 EventBus。为什么要使用 EventBus解耦合(轻松的实现系统间解耦)高性能可扩展每一个事件都是简单独立且不可更改的对象只需要保存新增的事件不涉及其他的变更删除操作系统审计每一个事件都是不可变更的每一个事件都是可追溯的...EventBus 整体架构IEventBase :所有的事件应该实现这个接口这个接口定义了事件的唯一id EventId 和事件发生的事件 EventAtIEventHandler定义了一个 Handle 方法来处理相应的事件IEventStore所有的事件的处理存储保存事件的 IEventHandler一般不会直接操作通过 EventBus 的订阅和取消订阅来操作 EventStoreIEventBus用来发布/订阅/取消订阅事件并将事件的某一个 IEventHandler 保存到 EventStore 或从 EventStore 中移除使用示例来看一个使用示例完整代码示例internal class EventTest
{ public static void MainTest() { var eventBus DependencyResolver.Current.ResolveServiceIEventBus(); eventBus.SubscribeCounterEvent, CounterEventHandler1(); eventBus.SubscribeCounterEvent, CounterEventHandler2(); eventBus.SubscribeCounterEvent, DelegateEventHandlerCounterEvent(); eventBus.Publish(new CounterEvent { Counter 1 }); eventBus.UnsubscribeCounterEvent, CounterEventHandler1(); eventBus.UnsubscribeCounterEvent, DelegateEventHandlerCounterEvent(); eventBus.Publish(new CounterEvent { Counter 2 }); }
}
internal class CounterEvent : EventBase
{ public int Counter { get; set; }
}
internal class CounterEventHandler1 : IEventHandlerCounterEvent
{ public Task Handle(CounterEvent event) { LogHelper.GetLoggerCounterEventHandler1().Info($Event Info: {event.ToJson()}, Handler Type:{GetType().FullName}); return Task.CompletedTask; }
}
internal class CounterEventHandler2 : IEventHandlerCounterEvent
{ public Task Handle(CounterEvent event) { LogHelper.GetLoggerCounterEventHandler2().Info($Event Info: {event.ToJson()}, Handler Type:{GetType().FullName}); return Task.CompletedTask; }
}具体实现EventStoreInMemory 实现EventStoreInMemory 是 IEventStore 将数据放在内存中的实现使用了 ConcurrentDictionary 以及 HashSet 来尽可能的保证高效具体实现代码如下public class EventStoreInMemory : IEventStore
{ private readonly ConcurrentDictionarystring, HashSetType _eventHandlers new ConcurrentDictionarystring, HashSetType(); public bool AddSubscriptionTEvent, TEventHandler() where TEvent : IEventBase where TEventHandler : IEventHandlerTEvent { var eventKey GetEventKeyTEvent(); if (_eventHandlers.ContainsKey(eventKey)) { return _eventHandlers[eventKey].Add(typeof(TEventHandler)); } else { return _eventHandlers.TryAdd(eventKey, new HashSetType() { typeof(TEventHandler) }); } } public bool Clear() { _eventHandlers.Clear(); return true; } public ICollectionType GetEventHandlerTypesTEvent() where TEvent : IEventBase { if(_eventHandlers.Count 0) return new Type[0]; var eventKey GetEventKeyTEvent(); if (_eventHandlers.TryGetValue(eventKey, out var handlers)) { return handlers; } return new Type[0]; } public string GetEventKeyTEvent() { return typeof(TEvent).FullName; } public bool HasSubscriptionsForEventTEvent() where TEvent : IEventBase { if(_eventHandlers.Count 0) return false; var eventKey GetEventKeyTEvent(); return _eventHandlers.ContainsKey(eventKey); } public bool RemoveSubscriptionTEvent, TEventHandler() where TEvent : IEventBase where TEventHandler : IEventHandlerTEvent { if(_eventHandlers.Count 0) return false; var eventKey GetEventKeyTEvent(); if (_eventHandlers.ContainsKey(eventKey)) { return _eventHandlers[eventKey].Remove(typeof(TEventHandler)); } return false; }
}EventBusInMemory 的实现从上面可以看到 EventStore 保存的是 IEventHandler 对应的 Type在 Publish 的时候根据 Type 从 IoC 容器中取得相应的 Handler 即可如果没有在 IoC 容器中找到对应的类型则会尝试创建一个类型实例然后调用 IEventHandler 的 Handle 方法代码如下/// summary
/// EventBus in memory
/// /summary
public class EventBus : IEventBus
{ private static readonly ILogHelperLogger Logger Helpers.LogHelper.GetLoggerEventBus(); private readonly IEventStore _eventStore; private readonly IServiceProvider _serviceProvider; public EventBus(IEventStore eventStore, IServiceProvider serviceProvider null) { _eventStore eventStore; _serviceProvider serviceProvider ?? DependencyResolver.Current; } public bool PublishTEvent(TEvent event) where TEvent : IEventBase { if (!_eventStore.HasSubscriptionsForEventTEvent()) { return false; } var handlers _eventStore.GetEventHandlerTypesTEvent(); if (handlers.Count 0) { var handlerTasks new ListTask(); foreach (var handlerType in handlers) { try { if (_serviceProvider.GetServiceOrCreateInstance(handlerType) is IEventHandlerTEvent handler) { handlerTasks.Add(handler.Handle(event)); } } catch (Exception ex) { Logger.Error(ex, $handle event [{_eventStore.GetEventKeyTEvent()}] error, eventHandlerType:{handlerType.FullName}); } } handlerTasks.WhenAll().ConfigureAwait(false); return true; } return false; } public bool SubscribeTEvent, TEventHandler() where TEvent : IEventBase where TEventHandler : IEventHandlerTEvent { return _eventStore.AddSubscriptionTEvent, TEventHandler(); } public bool UnsubscribeTEvent, TEventHandler() where TEvent : IEventBase where TEventHandler : IEventHandlerTEvent { return _eventStore.RemoveSubscriptionTEvent, TEventHandler(); }
}项目实例来看一个实际的项目中的使用在我的活动室预约项目中有一个公告的模块访问公告详情页面这个公告的访问次数加1把这个访问次数加1改成了用 EventBus 来实现实际项目代码https://github.com/WeihanLi/ActivityReservation/blob/67e2cb8e92876629a7af6dc051745dd8c7e9faeb/ActivityReservation/Startup.cs0. 定义 Event 以及 EventHandlerpublic class NoticeViewEvent : EventBase
{ public Guid NoticeId { get; set; } // UserId // IP // ...
}
public class NoticeViewEventHandler : IEventHandlerNoticeViewEvent
{ public async Task Handle(NoticeViewEvent event) { await DependencyResolver.Current.TryInvokeServiceAsyncReservationDbContext(async dbContext { var notice await dbContext.Notices.FindAsync(event.NoticeId); notice.NoticeVisitCount 1; await dbContext.SaveChangesAsync(); }); }
}这里的 Event 只定义了一个 NoticeId 其实也可以把请求信息如IP/UA等信息加进去在 EventHandler里处理以便日后数据分析。1. 注册 EventBus 相关服务以及 EventHandlersservices.AddSingletonIEventBus, EventBus();
services.AddSingletonIEventStore, EventStoreInMemory();
//register EventHandlers
services.AddSingletonNoticeViewEventHandler();2. 订阅事件public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IEventBus eventBus)
{ eventBus.SubscribeNoticeViewEvent, NoticeViewEventHandler(); // ...
}3. 发布事件eventBus.Publish(new NoticeViewEvent { NoticeId notice.NoticeId });Referencehttps://github.com/dotnet-architecture/eShopOnContainershttps://docs.microsoft.com/zh-cn/previous-versions/msp-n-p/jj591559(vpandp.10)https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/multi-container-microservice-net-applications/integration-event-based-microservice-communicationshttps://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/multi-container-microservice-net-applications/subscribe-eventshttps://github.com/sheng-jie/EventBushttps://github.com/WeihanLi/ActivityReservation