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

1.第一个点

在ABP中提供了对Action类型的支持,而我们的自己定义的类中只是针对继承了IEventHandler的接口的类

2.第二个点

在ABP中使用了线程安全的ConcurrentDictionary来存放映射关系,因为EventBus作为一个单例存在,这是必须要考虑的。ConcurrentDictionary虽然保证了字典的线程安全,但是并不能保证List的线程安全,可能存在同一时间同时插入相同的Handler,所以在上面的方法中使用了加锁的方式。

3.第三个点

从上面的源码中,我们可以看出EventBus使用了反射和容器(CastleWindsor)注入的方式触发,其实要实现完全解耦,实现灵活可配置,反射是一项必不可少的技术,但是凡事都都是讲究一个度,我们知道反射的缺点就是性能消耗比较大,随着反射技术的发展,反射的速度已经提升了许多,但是相对于直接调用,那还是存在一定的差距。但是只要讲究合理度,损耗一部分性能实现良好的系统,这是明智的。在上一篇随笔中,我们的所有的类型包括EventData和Eventhandler全部是使用的是反射的方式实现的,可想而知,这是消耗性能最大的,而在ABP中采用了加入的容器的方式,这将改善性能问题。其实还是那句话,容器这种接触耦合的方式还是离不开反射技术在里面。在Castle Windsor的源码中,它同样是维护了一个字典,只是将部分类通过反射的方式得到,来优化完全使用反射获取对象的方式。

4.第四个点

加入了异步的方式触发事件,通过重新开启一个线程的方式,提高执行的速度。

首先来完善第一个问题,其实在事件总线最开始的时候我们已经尝试定义了一个统一的Handler只不过那个Handler定义的有点过头了。。。。,这个我们可以参照一下ABP的源码中ActionEventHandler中的定义

  internal class ActionEventHandler<TEventData> :IEventHandler<TEventData> where TEventData:EventData
{
/// <summary>
/// Action委托具有一个TEventData类型的参数
/// </summary>
public Action<TEventData> Action { get; private set; }
/// <summary>
/// 因为就是为了统一创建Handler所以处理逻辑是通过构造函数传入而不是直接在Handle()方法中写死
/// </summary>
/// <param name="handler"></param>
public ActionEventHandler(Action<TEventData> handler)
{
Action = handler;
}
public void Handle(TEventData evetData)
{
Action(evetData);
}
}

我们在上一篇定义的Mouse类中,将我们的ActionHandler触发,简单的测试一下

 public void Come()
{
new ActionEventHandler<MouseEventData>((data)=>Console.WriteLine(data.Name)).Handle(new MouseEventData() { Name="小黄"});
//MouseEventHandler(new MouseEventData() { Name=this.Name});
//EventBus.Default.Trigger(new MouseEventData() { Name=this.Name});
}

第二个问题:解决并发性的问题此时需要用到锁,所以只需要在可能产生并发的代码中加入锁即可

  //尽量保证锁中的代码少
public static object lockObj=new object();
public void Register(Type dataType, Type handlerType)
{
lock (lockObj)
{
if (mapDic.Keys.Contains(dataType))
{
if (!mapDic[dataType].Contains(handlerType))
{
mapDic[dataType].Add(handlerType);
}
}
else
{
mapDic[dataType] = new List<Type>() { handlerType };
}
}
}
public void Unregister(Type eventType, Type handler)
{
lock (lockObj)
{
if (mapDic.Keys.Contains(eventType))
{
if (mapDic[eventType].Contains(handler))
{
mapDic[eventType].Remove(handler);
}
}
}
}

第四个问题:加入异步的处理方法,其实就是单独开启一个线程执行需要同步执行的代码而已

 public Task TriggerAsync<TEventData>(TEventData eventData) where TEventData : IEventData
{
return Task.Run(() => Trigger(eventData));
}
//调用一下
static void Main(string[] args)
{ EventBus.Default.Register(typeof(MouseEventData), typeof(CatchEventHandler));
Mouse m = new Mouse("老鼠1号");
EventBus.Default.TriggerAsync(new MouseEventData() { Name = "xiaohuang" });
m.Come();
Console.Read();
}

第三个问题,涉及到容器,这一部分内容较多,将在接下来的随笔中学习

ABP之事件总线(4)的更多相关文章

  1. ABP之事件总线(5)

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

  2. ABP之事件总线(3)

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

  3. ABP之事件总线(1)

    什么是事件总线呢?官方的文档说,它是一个单例对象,由其他的类共同拥有,可以用来触发和处理事件.这个东西确实比较陌生,为什么要使用事件总线,或者说事件总线的优势是什么???首先我们可以明确的是,事件总线 ...

  4. ABP的事件总线和领域事件(EventBus & Domain Events)

    http://www.aspnetboilerplate.com/Pages/Documents/EventBus-Domain-Events EventBus EventBus是个单例,获得Even ...

  5. ABP之事件总线(2)

    在上一篇文章中,我们复习了一下事件的经典的发布订阅模式,同时对是事件源和时间处理逻辑进行抽象统一,用起来也没有问题.但是还是有很多的问题,比如说我们Handle方法其实是违背了单一性的原则的,里面混杂 ...

  6. [Abp 源码分析]九、事件总线

    0.简介 事件总线就是订阅/发布模式的一种实现,本质上事件总线的存在是为了降低耦合而存在的. 从上图可以看到事件由发布者发布到事件总线处理器当中,然后经由事件总线处理器调用订阅者的处理方法,而发布者和 ...

  7. ABP理论学习之事件总线和领域事件

    返回总目录 本篇目录 事件总线 定义事件 触发事件 处理事件 句柄注册 取消注册 在C#中,我们可以在一个类中定义自己的事件,而其他的类可以注册该事件,当某些事情发生时,可以通知到该类.这对于桌面应用 ...

  8. ABP官方文档翻译 3.7 领域事件(事件总线)

    领域事件(事件总线) 事件总线 注入IEventBus 获取默认实例 定义事件 预定义事件 处理异常 实体更改 触发事件 处理事件 处理基础事件 处理者异常 处理多个事件 注册处理者 自动 手动 取消 ...

  9. ABP EventBus(事件总线)

    事件总线就是订阅/发布模式的一种实现    事件总线就是为了降低耦合 1.比如在winform中  到处都是事件 触发事件的对象  sender 事件的数据    e 事件的处理逻辑  方法体 通过E ...

随机推荐

  1. PAM 認 證 模 組

    作者:陳柏菁 E-mail 作用:限制哪些用户或者组可以从哪里登陆,或者可以建立/etc/nologin立即阻止一般用户登陆,限制 user可以使用的资源.例如cpu,文件,登陆数量,某些服务的登陆时 ...

  2. How to configure ESXi to boot via Software iSCSI?

    http://blogs.vmware.com/vsphere/2011/11/how-to-configure-esxi-to-boot-via-software-iscsi.html Introd ...

  3. sublime text3中文文件名显示为框框,怎么解决

    点击Preferences选项——settings {    "font_size": 20,    "ignored_packages":    [      ...

  4. 谈谈MySQL死锁之二 死锁检测和处理源码分析

    这一篇主要是通过一个实验来进行描述,过程是比较枯燥的. 实验准备 create table test_lock(id int auto_increment primary key ,stock int ...

  5. 手机APP UI设计尺寸基础知识

    从原理开始介绍一下移动端设计尺寸规范 初涉移动端设计和开发的同学们,基本都会在尺寸问题上纠结好一阵子才能摸到头绪.我也花了很长时间才弄明白,感觉有必要写一篇足够通俗易懂的教程来帮助大家.从原理说起,理 ...

  6. 【FTP】FTP服务器的搭建

    记录一下FTP服务器的搭建首先打开 程序和功能>打开或关闭Windows功能 进入到Windows功能界面:勾选FTP服务器.然后再在IIS界面,新建一个网站.右键网站,选择“添加到FTP发布” ...

  7. Benchmark Web App 性能瓶颈分析与性能测试工具的使用方法总结

    主要分为以下几个要素的指标: Disk IO . CPU . mem . Net . MySQL Web性能测试工具: 客户端 服务器端: 服务器性能测试工具: 服务器性能瓶颈分析工具: ab, si ...

  8. 设置Nginx以列表方式显示网站内容

    服务器目录内容: 访问该页面时,将所有文件和目录按列表方式显示 nginx配置文件

  9. 转移 Visual Studio 2017 的安装临时文件

    每次更新 Visual Studio 2017 会在 C 盘留下大量的缓存文件,因为目录比较深,怕以后忘了,用目录链接的形式转移到其它磁盘,也好方便清理: mklink /D C:\ProgramDa ...

  10. 揭开Redis的神秘面纱

    本篇博文将为你解开Redis的神秘面纱,通过阅读本篇博文你将了解到以下内容: 什么是Redis? 为什么选择 Redis? 什么场景下用Redis? Redis 支持哪些语言? Redis下载 Red ...