ABP EventBus(事件总线)
事件总线就是订阅/发布模式的一种实现 事件总线就是为了降低耦合
1.比如在winform中 到处都是事件

触发事件的对象 sender
事件的数据 e
事件的处理逻辑 方法体
通过EventBus实现事件对象和处理逻辑的解耦

1.抽离事件对象 发生时间的事件 触发事件的对象源(可选)
//
// 摘要:
// Defines interface for all Event data classes.
public interface IEventData
{
//
// 摘要:
// The time when the event occured.
DateTime EventTime { get; set; }
//
// 摘要:
// The object which triggers the event (optional).
object EventSource { get; set; }
2.抽离事件的处理对象
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);
}
3.所有EventData跟EventHandler不再耦合 全都跟EventBus进行通信
在EventBus中有一个字典进行存放 EventData类型跟需要触发的Handler对象
这里的Type就是EventData List<IEventHandlerFactory>>就是存放处理当前EventData的多个Handler
private readonly ConcurrentDictionary<Type, List<IEventHandlerFactory>> _handlerFactories;
4.ABP的EventBus封装的比较高深 自己来个简洁版 思想是一样的(这里还存在很多问题 比如并发 往字典存放数据没有加锁等问题 具体的看ABP)
ABP初始化的时候会把所有的EventData和EventHandler对应存放到字典中 也可以通过Unregister移除某一个Handler
public class EventBus : IEventBus
{
public EventBus()
{
mapDic = new ConcurrentDictionary<Type, List<Type>>();
}
//EventBus单例模式
public static EventBus Default = new EventBus();
//存储EventData和EventHandle的映射关系(没有存放handler的实例而是存放metaData,然后通过反射调用)
private ConcurrentDictionary<Type, List<Type>> mapDic; public void Register<TEventData>(Type handlerType) where TEventData : IEventData
{
//将数据存储到mapDic
var dataType = typeof(TEventData);
Register(dataType, handlerType);
} public void Register(Type eventType, Type handlerType)
{
if (mapDic.Keys.Contains(eventType))
{
if (!mapDic[eventType].Contains(handlerType))
{
mapDic[eventType].Add(handlerType);
}
}
else
{
mapDic[eventType] = new List<Type>() { handlerType };
}
} public void Unregister<TEventData>(Type handler) where TEventData : IEventData
{
var dataType = typeof(TEventData);
Unregister(dataType, handler);
} public void Unregister(Type eventType, Type handlerType)
{
if (mapDic.Keys.Contains(eventType))
{
if (mapDic[eventType].Contains(handlerType))
{
mapDic[eventType].Remove(handlerType);
}
}
} public void Trigger<TEventData>(TEventData eventData) where TEventData : IEventData
{
var dataType = eventData.GetType();
//获取当前的EventData绑定的所有Handler
var handlerTypes = mapDic[dataType];
foreach (var handlerType in handlerTypes)
{
var methodInfo = handlerType.GetMethod("EventHandle");
if (methodInfo != null)
{
// var handler = Assembly.GetExecutingAssembly().CreateInstance(handlerType.FullName);
var handler = Activator.CreateInstance(handlerType);
//执行所有的Handler方法
methodInfo.Invoke(handler, new object[] { eventData });
}
}
}
}
提供了EventData和Handler的绑定 也可以移除指定的Handler
通过调用.Trigger() 然后当前的EventData类型在字典中找到当前类型的所有Handler 执行所有Handler的处理方法
事件总线通过 EventBusInstaller 来注册 EventBus 和监听事件。 每当IocContainer注册一个类型后 会判断当前类型是否实现IEventHandler 获取具体的EventData类型在EventBus上进行注册
private void Kernel_ComponentRegistered(string key, IHandler handler)
{
/* This code checks if registering component implements any IEventHandler<TEventData> interface, if yes,
* gets all event handler interfaces and registers type to Event Bus for each handling event.
*/
if (!typeof(IEventHandler).GetTypeInfo().IsAssignableFrom(handler.ComponentModel.Implementation))
{
return;
} var interfaces = handler.ComponentModel.Implementation.GetTypeInfo().GetInterfaces();
foreach (var @interface in interfaces)
{
if (!typeof(IEventHandler).GetTypeInfo().IsAssignableFrom(@interface))
{
continue;
} var genericArgs = @interface.GetGenericArguments();
if (genericArgs.Length == )
{
_eventBus.Register(genericArgs[], new IocHandlerFactory(_iocResolver, handler.ComponentModel.Implementation));
}
}
}
在ABP中使用EventBus
1.定义自己的数据对象
public class MyEventData : EventData
{
public string Name { get; set; }
}
2.定义自己的处理事件Handler
public class MyEventHandler : IEventHandler<MyEventData>, ITransientDependency
{
public ILogger Logger { set; get; }
public MyEventHandler()
{
Logger = NullLogger.Instance;
}
public void HandleEvent(MyEventData eventData)
{
Logger.Info($"这是{eventData.Name}自定义的HandEvent处理事件");
}
}
3.通过属性注入 或者构造函数注入 或者直接用静态实例
public class TaskAppService : ApplicationService
{
public IEventBus EventBus { get; set; } public TaskAppService()
{
EventBus = NullEventBus.Instance;
} public void CompleteTask(CompleteTaskInput input)
{
EventBus.Trigger(new MyEventData {Name= "abc123"});
}
}
EventBus.Default.Trigger(new MyEventData {Name= "abc123"});
https://www.cnblogs.com/myzony/p/9413351.html
ABP EventBus(事件总线)的更多相关文章
- Guava - EventBus(事件总线)
Guava在guava-libraries中为我们提供了事件总线EventBus库,它是事件发布订阅模式的实现,让我们能在领域驱动设计(DDD)中以事件的弱引用本质对我们的模块和领域边界很好的解耦设计 ...
- EventBus(事件总线)
EventBus(事件总线) Guava在guava-libraries中为我们提供了事件总线EventBus库,它是事件发布订阅模式的实现,让我们能在领域驱动设计(DDD)中以事件的弱引用本质对我们 ...
- dhroid - eventbus 事件总线
你听过onClick 事件,onItemClick 事件,事件总线不一定听过吧, eventbus 事件总线也是一个编程思想,为什么要设计EventBus了,因为他是领域驱动设计中比不可少的模块,它承 ...
- EventBus事件总线
EventBus事件总线的使用-自己实现事件总线 在C#中,我们可以在一个类中定义自己的事件,而其他的类可以订阅该事件,当某些事情发生时,可以通知到该类.这对于桌面应用或者独立的windows服务 ...
- ABP之事件总线(5)
前面已经对Castle Windsor的基本使用进行了学习,有了这个基础,接下来我们将把我们的事件总线再次向ABP中定义的事件总线靠近.从源码中可以知道在ABP中定义了Dictionary,存放三种类 ...
- ABP之事件总线(4)
在上一篇的随笔中,我们已经初步完成了EventBus,但是EventBus中还有诸多的问题存在,那么到底有什么问题呢,接下来我们需要看一看ABP中的源码是如何定义EventBus的. 1.第一个点 在 ...
- ABP之事件总线(3)
承接上一篇时间总线的学习,在上一篇中我们实现了取消显式注册事件的方式,采用使用反射的方式.这样的好处可以解除Publisher和Scriber的显式依赖,但是问题又来了,因为我们只有Publisher ...
- EventBus 事件总线 案例
简介 地址:https://github.com/greenrobot/EventBus EventBus是一个[发布 / 订阅]的事件总线.简单点说,就是两人[约定]好怎么通信,一人发布消息,另外一 ...
- C#总结(六)EventBus事件总线的使用-自己实现事件总线
在C#中,我们可以在一个类中定义自己的事件,而其他的类可以订阅该事件,当某些事情发生时,可以通知到该类.这对于桌面应用或者独立的windows服务来说是非常有用的.但对于一个web应用来说是有点问题的 ...
- Android 开发 框架系列 EventBus 事件总线
介绍 GitHub:https://github.com/greenrobot/EventBus 先聊聊EventBus 线程总线是干什么的,使用环境,优点.缺点. 干什么的? 一句话,简单统一数据传 ...
随机推荐
- python处理Excel - xlrd xlwr openpyxl
python处理Excel - xlrd xlwr openpyxl 1 xlrd和xlwt Todo: 使用xlrd和xlwt读写Excel文件的方法和示例代码,待续... 参考链接: Creati ...
- Jmeter GIS调用-->参数化+正则表达式提取器+后置处理器+逻辑控制器
一.参数化: 1.添加线程组 2.添加HTTP请求 3.CSV 数据文件设置 HTTP请求参数话 4.正则表达式提取器 5.逻辑控制器 可以or and 等 6.后置处理器写入文件 FileWr ...
- java的冒泡排序
public interface Sorter{ public <T extends Comparable<T>> void sort(T[] list); //定义两个待排序 ...
- Jmeter笔记(Ⅱ)使用Jmeter实现轻量级的接口自动化测试
接口测试虽然作为版本的一环,但是也是有一套完整的体系,有接口的功能测试.性能测试.安全测试:同时,由于接口的特性,接口的自动化低成本高收益的,使用一些开源工具或一些轻量级的方法,在测试用例开发的成本不 ...
- golang 基本数据结构使用
1 goalng struct 1.1 var s1 student 1.2 s2 := student {"zhou", 33} 1.3 s3 := student {Name: ...
- 创建 Visual Studio 2017 离线安装
代码示例: vs_Enterprise.exe --layout E:\VS2017LAYOUT --add Microsoft.VisualStudio.Workload.NetCoreTools ...
- asp.net的<% %>特定用法
在asp.net应用程序中,在asp.net页面常用的<%@ %>.<%# %>.<%= %>.在全球化的项目中使用<%$ %>绑定资源项目,在asp. ...
- react问题解决的一些方法
原文链接: https://segmentfault.com/a/1190000007811296?utm_source=tuicool&utm_medium=referral 初学者对Rea ...
- MVC-Razor视图
Razor 视图引擎 与Aspx开发区别在于代码: 1.Razor 更智能,摒弃了<%%>格式,直接用@符号开启cs代码,遇到html时自动识别 2.遇到如汉字等即非cs代码,又非html ...
- redis 在 php 中的应用(key篇)
本文为我阅读了 redis参考手册 之后结合 博友的博客 编写,注意 php_redis 和 redis-cli 的区别(主要是返回值类型和参数用法) 目录: KEY(键) DEL ...