[Architect] Abp 框架原理解析(2) EventBus
本节目录
原理介绍
事件总线大致原理:
(1) 在事件总线内部维护着一个事件与事件处理程序相映射的字典。
(2) 利用反射,事件总线会将实现了IEventHandler的处理程序与相应事件关联到一起,相当于实现了事件处理程序对事件的订阅。
(3) 当发布事件时,事件总线会从字典中找出相应的事件处理程序,然后利用反射去调用事件处理程序中的方法。
Abp源码分析
1.AbpKernelModule的Initialize方法
2.EventBusInstaller的Install方法
3.Kernel_ComponentRegistered
以上将事件注册完成了.
剩下就需要如何触发了.
触发实际上是写在代码里的,最终调用的其实还是EventBus.Trigger()
代码实现
看完Abp的实现,关键点还是反射以及IoC注册对象事件的拦截.
先上实现效果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | interface IPerson { void Say(); } class Person : IPerson { public IEventBus EventBus { get ; set ; } public void Say() { var str = "Say" ; Console.WriteLine(str); EventBus.Trigger( typeof (SayEventData), this , new SayEventData() { Content = str }); } } |
定义上面需要的EventData,实际这是事件基类.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | [Serializable] public abstract class EventData : IEventData { public DateTime EventTime { get ; set ; } /// <summary> /// The object which triggers the event (optional). /// </summary> public object EventSource { get ; set ; } protected EventData() { EventTime = DateTime.Now; } } public interface IEventData { DateTime EventTime { get ; set ; } object EventSource { get ; set ; } } |
自定义事件,继承事件基类,可以添加事件需要传递的数据.
1 2 3 4 | public class SayEventData : EventData { public string Content { get ; set ; } } |
定义IEventHandle,实际这是事件处理程序,一个事件一般对应多个事件处理程序.
1 2 3 4 5 6 7 8 9 10 11 12 | public interface IEventHandler { } public interface IEventHandler< in TEventData> : IEventHandler { /// <summary> /// Handler handles the event by implementing this method. /// </summary> /// <param name="eventData">Event data</param> void HandleEvent(TEventData eventData); } |
自定义的EventHandle,各种事件订阅器.
1 2 3 4 5 6 7 | public class SayEvent : IEventHandler<SayEventData> { public void HandleEvent(SayEventData eventData) { Console.WriteLine( "进入事件啦:" + eventData.Content); } } |
事件总线EventBus,管理事件的中心.可以细化接口.
1 2 3 4 5 6 | public interface IEventBus { void Register(Type eventType, IEventHandler handler); void Trigger(Type eventType, object eventSource, IEventData eventData); } |
EventBus实现,核心是反射调用事件处理程序.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | public class EventBus : IEventBus { public static EventBus Default { get { return DefaultInstance; } } private static readonly EventBus DefaultInstance = new EventBus(); private readonly Dictionary<Type, List<IEventHandler>> _eventHandlers; public EventBus() { _eventHandlers = new Dictionary<Type, List<IEventHandler>>(); } public void Register(Type eventType, IEventHandler handler) { GetOrCreateHandlerFactories(eventType).Add(handler); } private List<IEventHandler> GetOrCreateHandlerFactories(Type eventType) { List<IEventHandler> handlers; if (!_eventHandlers.TryGetValue(eventType, out handlers)) { _eventHandlers[eventType] = handlers = new List<IEventHandler>(); } return handlers; } public void Trigger(Type eventType, object eventSource, IEventData eventData) { eventData.EventSource = eventSource; var handles = GetOrCreateHandlerFactories(eventType); if (handles.Count > 0) { foreach ( var eventHandler in handles) { if (eventHandler == null ) { throw new Exception( "Registered event handler for event type " + eventType.Name + " does not implement IEventHandler<" + eventType.Name + "> interface!" ); } //eventHandler. var handlerType = typeof (IEventHandler<>).MakeGenericType(eventType); handlerType .GetMethod( "HandleEvent" , BindingFlags.Public | BindingFlags.Instance, null , new [] { eventType }, null ) .Invoke(eventHandler, new object [] { eventData }); } } } } |
执行,来测试是否通了.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | private static IEventBus _eventBus; static void Main( string [] args) { var container = IocManager.Instance.IocContainer; container.Register(Component.For<IEventBus>().Instance(EventBus.Default)); _eventBus = container.Resolve<IEventBus>(); container.Kernel.ComponentRegistered += Kernel_ComponentRegistered; //在Abp中,由于注册了所有ITransientDependency,所以这2个不需要手动注册 container.Register(Component.For<Person, IPerson>()); container.Register(Component.For<IEventHandler<SayEventData>, SayEvent>()); container.Resolve<IPerson>().Say(); Console.ReadKey(); } |
注册事件的绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | private static void Kernel_ComponentRegistered( string key, IHandler handler) { if (! typeof (IEventHandler).IsAssignableFrom(handler.ComponentModel.Implementation)) { return ; } var interfaces = handler.ComponentModel.Implementation.GetInterfaces(); foreach ( var @ interface in interfaces) { if (! typeof (IEventHandler).IsAssignableFrom(@ interface )) { continue ; } var genericArgs = @ interface .GetGenericArguments(); if (genericArgs.Length == 1) { //_eventBus.Register(genericArgs[0], handler.ComponentModel.Implementation.CreateInstance<IEventHandler>()); _eventBus.Register(genericArgs[0], (IEventHandler)IocManager.Instance.IocContainer.Resolve(handler.ComponentModel.Implementation)); } } } |
至此,事件成功执行
本文地址:http://www.cnblogs.com/neverc/p/5254859.html
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 如果觉得还有帮助的话,可以点一下右下角的【推荐】,希望能够持续的为大家带来好的技术文章!想跟我一起进步么?那就【关注】我吧。
分类:
[15]Architect
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义