事件总线就是订阅/发布模式的一种实现 事件总线就是为了降低耦合
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 线程总线是干什么的,使用环境,优点.缺点. 干什么的? 一句话,简单统一数据传 ...
随机推荐
-
4.2 CUDA Reduction 一步一步优化
Reduction并行分析: 每个线程是基于一个树状的访问模型,从上至下,上一层读取数据相加得到下一层的数据.不停的迭代,直到访问完所有的数据. 利用这么多的线程块(thread block)我们需要 ...
-
ImageMagick 使用经验
from:http://community.itbbs.cn/thread/20402/ 1.如何用ImageMagic水平或垂直拼接图片 因为是分片下载的,现在只能用montage拼接图片列阵,但如 ...
-
AutoCAD神器! AutoCAD自动切换中英文输入法插件(ZDSRF)
AutoCAD神器! AutoCAD自动切换中英文输入法插件 (一)功能特点: CAD命令中只能输入英文字符,不能输入中文,在文字编辑.文字输入.尺寸编辑中经常需要输入中文,此时就需要频繁的切换输入法 ...
-
zookeeper学习笔记记录
zookeeper的概述: ZooKeeper 本质上是一个分布式的小文件存储系统.提供基于类似于文件系统的目录树方式的数据存储,并且可以对树中的节点进行有效管理.从而用来维护和监控你存储的数据的状态 ...
-
009_python魔法函数
11. (译)Python魔法方法指南 原文: http://www.rafekettler.com/magicmethods.html 原作者: Rafe Kettler 翻译: hit9 原版(英 ...
-
leetcode1020
class Solution(object): def __init__(self): self.cons = 0 self.S = list() def dfs(self,m,n,v,A): whi ...
-
[ASP.NET]Net Framework环境问题的一种修复方案
一.情况介绍 造价软件基于.net framework 4.0开发,要成功运行需要在目标电脑上安装4.0版本以上的framework.一般情况下xp是没有的,win7系列自带3.5,都需要手动安装4. ...
-
无监控不运维——使用 Python 写一个小小的项目监控
在公司里做的一个接口系统,主要是对接第三方的系统接口,所以,这个系统里会和很多其他公司的项目交互.随之而来一个很蛋疼的问题,这么多公司的接口,不同公司接口的稳定性差别很大,访问量大的时候,有的不怎么行 ...
-
C语言的 32个关键之和9个控制语言之关键字
auto break case char const continue default do double else enum extern float for goto ...
-
nginx的源代码分析--间接回调机制的使用和类比
nginx使用了间接回调机制.结合upstream机制的使用来说明一下,首先明白几个事实: 1)事实上ngxin和下游client的连接使用的是ngx_http_connection_t,每一个连接相 ...