ABP之事件总线(4)
在上一篇的随笔中,我们已经初步完成了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)的更多相关文章
- ABP之事件总线(5)
前面已经对Castle Windsor的基本使用进行了学习,有了这个基础,接下来我们将把我们的事件总线再次向ABP中定义的事件总线靠近.从源码中可以知道在ABP中定义了Dictionary,存放三种类 ...
- ABP之事件总线(3)
承接上一篇时间总线的学习,在上一篇中我们实现了取消显式注册事件的方式,采用使用反射的方式.这样的好处可以解除Publisher和Scriber的显式依赖,但是问题又来了,因为我们只有Publisher ...
- ABP之事件总线(1)
什么是事件总线呢?官方的文档说,它是一个单例对象,由其他的类共同拥有,可以用来触发和处理事件.这个东西确实比较陌生,为什么要使用事件总线,或者说事件总线的优势是什么???首先我们可以明确的是,事件总线 ...
- ABP的事件总线和领域事件(EventBus & Domain Events)
http://www.aspnetboilerplate.com/Pages/Documents/EventBus-Domain-Events EventBus EventBus是个单例,获得Even ...
- ABP之事件总线(2)
在上一篇文章中,我们复习了一下事件的经典的发布订阅模式,同时对是事件源和时间处理逻辑进行抽象统一,用起来也没有问题.但是还是有很多的问题,比如说我们Handle方法其实是违背了单一性的原则的,里面混杂 ...
- [Abp 源码分析]九、事件总线
0.简介 事件总线就是订阅/发布模式的一种实现,本质上事件总线的存在是为了降低耦合而存在的. 从上图可以看到事件由发布者发布到事件总线处理器当中,然后经由事件总线处理器调用订阅者的处理方法,而发布者和 ...
- ABP理论学习之事件总线和领域事件
返回总目录 本篇目录 事件总线 定义事件 触发事件 处理事件 句柄注册 取消注册 在C#中,我们可以在一个类中定义自己的事件,而其他的类可以注册该事件,当某些事情发生时,可以通知到该类.这对于桌面应用 ...
- ABP官方文档翻译 3.7 领域事件(事件总线)
领域事件(事件总线) 事件总线 注入IEventBus 获取默认实例 定义事件 预定义事件 处理异常 实体更改 触发事件 处理事件 处理基础事件 处理者异常 处理多个事件 注册处理者 自动 手动 取消 ...
- ABP EventBus(事件总线)
事件总线就是订阅/发布模式的一种实现 事件总线就是为了降低耦合 1.比如在winform中 到处都是事件 触发事件的对象 sender 事件的数据 e 事件的处理逻辑 方法体 通过E ...
随机推荐
- What is `^M` and how do I get rid of it?
When I open the file in vim, I am seeing strange ^M characters. Unfortunately, the world's favorite ...
- tmux的复制粘贴
tmux有面板的概念,这导致普通终端下的ctrl+shift+C的模式复制出来的文本会串行.如果面板只有一列当然没有问题,但当面板有多列时,复制就会出问题.于是tmux提出了类似vim的复制模式.因此 ...
- 基于Centos搭建 Mono 开发环境
系统要求: CentOS 7.2 64 位操作系统 安装 Mono 安装前的准备 yum install yum-utils 执行命令添加安装包仓库 rpm --import "http:/ ...
- git checkout -b mybranch和git checkout mybranch
创建分支: $ git branch mybranch切换分支: $ git checkout mybranch创建并切换分支: $ git checkout -b mybranch更新maste ...
- oracle登陆提示“ora-01031 insufficient privileges”
本机装了服务端的oracle11.2g,一直没用,中间换过系统的登陆用户.今早发现登陆数据库时发现老提示“ora-01031 insufficient privileges”,以为监听没配置好,试过了 ...
- docker镜像、容器以及命令操作
docker image docker image是一个极度精简版的Linux程序运行环境,官网的java镜像包括的东西更少,除非是镜像叠加方式的如centos+java7 docker image是 ...
- Atitit 验证 数字验证 非空验证的最佳算法 h5
Atitit 验证 数字验证 非空验证的最佳算法 h5 <td><select class="searchBox-select" style=" ...
- 物联网架构成长之路(11)-Redis缓存主从复制
1. 说明 在我的物联网平台框架框架中,会用到Redis这个中间件.作为EMQ权限认证的缓存.https://www.cnblogs.com/think-in-java/p/5123884.html ...
- 使用自定义端口连接SQL Server 的方法
SQL默认是1433,使用MSSL连接时默认不需要加端口号,但是在修改了SQL端口之后,就需要添加自定义端口号了,加端口号使用的是逗号(,)而不是冒号(:). 看一下连接截图吧
- Android开发(十九)——ViewFlipper中的onClick事件和onFling事件冲突
在onDown中设置this.flipper.setClickable(true); 然后在onFling方法中this.flipper.setClickable(false); ps: 其中setO ...