在上一篇的随笔中,我们已经初步完成了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. XMR恶意挖矿脚本处理笔记

    一.登录 攻击者如何登录系统未能查出,所有日志已被清除.为防万一,把系统中没用的用户都删掉并修改其他用户密码. 二.被攻击后的表象 1.服务器资源被大量占用,资源占用率飙升: 2.服务器所有JS文件被 ...

  2. JVM 基础:回收哪些内存/对象 引用计数算法 可达性分析算法 finalize()方法 HotSpot实现分析

    转自:https://blog.csdn.net/tjiyu/article/details/53982412 1-1.为什么需要了解垃圾回收 目前内存的动态分配与内存回收技术已经相当成熟,但为什么还 ...

  3. sql server Local Service, Local System or Network Service

    local system account local system 选项指定一个不需要密码的本地系统账号去连接同一台电脑的sql server.local system account会限制sql s ...

  4. java 对一个字符串进行加减乘除的运算

    记录一个小程序,里面涉及到的JAVA知识点有:字符串扫描,list删除元素的方法,泛型的使用,JAVA中的/要注意的事项.有兴趣的可以看看 package com.demo; import java. ...

  5. 【C语言】字节对齐问题(以32位系统为例)

    1. 什么是对齐? 现代计算机中内存空间都是按照字节(byte)划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型 ...

  6. Keepalived源码安装

    1.编译.安装 # tar -xvf keepalived-1.3.9.tar.gz # cd keepalived-1.3.9/ # ./configure -prefix=/usr/local/k ...

  7. nodeJs--模块module.exports与实例化方法

    在nodejs中,提供了exports 和 require 两个对象,其中 exports 是模块公开的接口,require 用于从外部获取一个模块的接口,即所获取模块的 exports 对象.而在e ...

  8. s:iterator 标签使用错误记录

    <s:iterator value="newMarriageMoveList" id='tpNewMarriage' status="number"> ...

  9. DataTable转成List集合

    项目开发中,经常会获取到DataTable对象,如何把它转化成一个List对象呢?前几天就碰到这个问题,网上搜索整理了一个万能类,用了泛型和反射的知识.共享如下: public class Model ...

  10. 【R作图】蜜蜂群图beeswarm和jitter的使用

    最近经常要画好看的盒形图,还要在上面加入散点,所以总结了两个方法. 第一种方法是,利用beeswarm函数: library(beeswarm) beeswarm 蜜蜂群图 http://rgm3.l ...