ABP EventBus(事件总线)

时间:2022-06-15 13:11:31

事件总线就是订阅/发布模式的一种实现    事件总线就是为了降低耦合

1.比如在winform中  到处都是事件

ABP EventBus(事件总线)

触发事件的对象  sender

事件的数据    e

事件的处理逻辑  方法体

通过EventBus实现事件对象和处理逻辑的解耦

ABP 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(事件总线)的更多相关文章

  1. Guava - EventBus&lpar;事件总线&rpar;

    Guava在guava-libraries中为我们提供了事件总线EventBus库,它是事件发布订阅模式的实现,让我们能在领域驱动设计(DDD)中以事件的弱引用本质对我们的模块和领域边界很好的解耦设计 ...

  2. EventBus&lpar;事件总线&rpar;

    EventBus(事件总线) Guava在guava-libraries中为我们提供了事件总线EventBus库,它是事件发布订阅模式的实现,让我们能在领域驱动设计(DDD)中以事件的弱引用本质对我们 ...

  3. dhroid - eventbus 事件总线

    你听过onClick 事件,onItemClick 事件,事件总线不一定听过吧, eventbus 事件总线也是一个编程思想,为什么要设计EventBus了,因为他是领域驱动设计中比不可少的模块,它承 ...

  4. EventBus事件总线

    EventBus事件总线的使用-自己实现事件总线   在C#中,我们可以在一个类中定义自己的事件,而其他的类可以订阅该事件,当某些事情发生时,可以通知到该类.这对于桌面应用或者独立的windows服务 ...

  5. ABP之事件总线&lpar;5&rpar;

    前面已经对Castle Windsor的基本使用进行了学习,有了这个基础,接下来我们将把我们的事件总线再次向ABP中定义的事件总线靠近.从源码中可以知道在ABP中定义了Dictionary,存放三种类 ...

  6. ABP之事件总线&lpar;4&rpar;

    在上一篇的随笔中,我们已经初步完成了EventBus,但是EventBus中还有诸多的问题存在,那么到底有什么问题呢,接下来我们需要看一看ABP中的源码是如何定义EventBus的. 1.第一个点 在 ...

  7. ABP之事件总线&lpar;3&rpar;

    承接上一篇时间总线的学习,在上一篇中我们实现了取消显式注册事件的方式,采用使用反射的方式.这样的好处可以解除Publisher和Scriber的显式依赖,但是问题又来了,因为我们只有Publisher ...

  8. EventBus 事件总线 案例

    简介 地址:https://github.com/greenrobot/EventBus EventBus是一个[发布 / 订阅]的事件总线.简单点说,就是两人[约定]好怎么通信,一人发布消息,另外一 ...

  9. C&num;总结(六)EventBus事件总线的使用-自己实现事件总线

    在C#中,我们可以在一个类中定义自己的事件,而其他的类可以订阅该事件,当某些事情发生时,可以通知到该类.这对于桌面应用或者独立的windows服务来说是非常有用的.但对于一个web应用来说是有点问题的 ...

  10. Android 开发 框架系列 EventBus 事件总线

    介绍 GitHub:https://github.com/greenrobot/EventBus 先聊聊EventBus 线程总线是干什么的,使用环境,优点.缺点. 干什么的? 一句话,简单统一数据传 ...

随机推荐

  1. 4&period;2 CUDA Reduction 一步一步优化

    Reduction并行分析: 每个线程是基于一个树状的访问模型,从上至下,上一层读取数据相加得到下一层的数据.不停的迭代,直到访问完所有的数据. 利用这么多的线程块(thread block)我们需要 ...

  2. ImageMagick 使用经验

    from:http://community.itbbs.cn/thread/20402/ 1.如何用ImageMagic水平或垂直拼接图片 因为是分片下载的,现在只能用montage拼接图片列阵,但如 ...

  3. AutoCAD神器! AutoCAD自动切换中英文输入法插件(ZDSRF)

    AutoCAD神器! AutoCAD自动切换中英文输入法插件 (一)功能特点: CAD命令中只能输入英文字符,不能输入中文,在文字编辑.文字输入.尺寸编辑中经常需要输入中文,此时就需要频繁的切换输入法 ...

  4. zookeeper学习笔记记录

    zookeeper的概述: ZooKeeper 本质上是一个分布式的小文件存储系统.提供基于类似于文件系统的目录树方式的数据存储,并且可以对树中的节点进行有效管理.从而用来维护和监控你存储的数据的状态 ...

  5. 009&lowbar;python魔法函数

    11. (译)Python魔法方法指南 原文: http://www.rafekettler.com/magicmethods.html 原作者: Rafe Kettler 翻译: hit9 原版(英 ...

  6. leetcode1020

    class Solution(object): def __init__(self): self.cons = 0 self.S = list() def dfs(self,m,n,v,A): whi ...

  7. &lbrack;ASP&period;NET&rsqb;Net Framework环境问题的一种修复方案

    一.情况介绍 造价软件基于.net framework 4.0开发,要成功运行需要在目标电脑上安装4.0版本以上的framework.一般情况下xp是没有的,win7系列自带3.5,都需要手动安装4. ...

  8. 无监控不运维——使用 Python 写一个小小的项目监控

    在公司里做的一个接口系统,主要是对接第三方的系统接口,所以,这个系统里会和很多其他公司的项目交互.随之而来一个很蛋疼的问题,这么多公司的接口,不同公司接口的稳定性差别很大,访问量大的时候,有的不怎么行 ...

  9. C语言的 32个关键之和9个控制语言之关键字

    auto   break  case  char  const  continue  default  do double  else  enum  extern  float for  goto  ...

  10. nginx的源代码分析--间接回调机制的使用和类比

    nginx使用了间接回调机制.结合upstream机制的使用来说明一下,首先明白几个事实: 1)事实上ngxin和下游client的连接使用的是ngx_http_connection_t,每一个连接相 ...