在上一篇的随笔中,我们已经初步完成了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. [转]POJ3624 Charm Bracelet(典型01背包问题)

    来源:https://www.cnblogs.com/jinglecjy/p/5674796.html 题目链接:http://bailian.openjudge.cn/practice/4131/ ...

  2. js获取过滤条件中参数的快捷方式

    // window.location.href = "topupRecordController.do?exportExcel&" + encodeURI($(" ...

  3. Linux 内存机制【转载】

    原文地址:http://blog.csdn.net/tianlesoftware/article/details/5463790 一. 内存使用说明 Free 命令相对于top 提供了更简洁的查看系统 ...

  4. OkHttp踩坑记:为何 response.body().string() 只能调用一次?

    想必大家都用过或接触过 OkHttp,我最近在使用 Okhttp 时,就踩到一个坑,在这儿分享出来,以后大家遇到类似问题时就可以绕过去. 只是解决问题是不够的,本文将 侧重从源码角度分析下问题的根本, ...

  5. 《Redis入门指南(第2版)》读后感

    今天刚刚将此书看完,现在还能记住一些内容,还有一些感慨感想,正好又想写点什么了就随便记录一下吧!也许灵感明天就消失了呢? 首先觉得作者非常的厉害,年纪轻轻的就写出了这么一本非常不错的书籍! 然后就是对 ...

  6. Java注解应用,自定义注解映射实现方案说明.

    插件结构如图: 注册模块定义了三个:用于实体与表映射的注解,用于属性到表字段的映射,用于映射时过滤掉的注解. 1.用于实体与表映射的注解 package com.dobby.plugins.annot ...

  7. python + django + dwebsocket 实现简单的聊天室

    使用库dwebsocket,具体参考此处 views.py: from dwebsocket.decorators import accept_websocket,require_websocket ...

  8. 自己实现字符串转整数(不使用JDK的字符串转整数的方法)

    [需求]: (1)如果输入的字符串为null,为空,或者不是数字,抛出异常: (2)如果输入的数字超出int的最大值或最小值,抛出异常: (3)输入的数字允许以+或-号开头,但如果输入的字符串只有&q ...

  9. Java知多少(54)断言详解

    断言的概念 断言用于证明和测试程序的假设,比如“这里的值大于 5”.断言可以在运行时从代码中完全删除,所以对代码的运行速度没有影响. 断言的使用 断言有两种方法: 一种是 assert<< ...

  10. JDK8+Tomcat8配置https【转】

    生成密钥对 我比较喜欢密钥对这个名字,因为它非常明确了HTTPS在传输过程中需要的两个钥匙(公钥和私钥).如果不太了解HTTPS的,可以要到搜索引擎去搜索一下HTTPS的原理. 首先,确保java的目 ...