ABP之事件总线(5)
前面已经对Castle Windsor的基本使用进行了学习,有了这个基础,接下来我们将把我们的事件总线再次向ABP中定义的事件总线靠近。从源码中可以知道在ABP中定义了Dictionary,存放三种类型的Factory,然后通过容器的方式实例化相应的handlerfactory。承接前面的随笔,我们为什么要使用IOC?
IOC是用来代替反射的。那么反射在我们EventBus中有什么功能?反射是用来创建handler的实例的。那么我们的容器其实就是用来初始化实例这么一点功能的,所以我们不需要过多的改动我们以前的代码,只需加入容器的注入,同时在初始化的时候将反射的方式改为容器的方式。
IOCEventBus(第一种)
using Castle.MicroKernel.Registration;
using Castle.Windsor;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace EventBus
{
public class IOCEventBus : IEventBus
{
private IOCEventBus()
{
IocContainer = new WindsorContainer();
mapDic = new ConcurrentDictionary<Type, List<Type>>(); }
//EventBus单例模式
public static IOCEventBus Default = new IOCEventBus();
public IWindsorContainer IocContainer { get; private set; }
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 dataType, Type handlerType)
{
//注册IEventHandler<T>到IOC容器
var handlerInterface = handlerType.GetInterface("IEventHandler`1");
if (!IocContainer.Kernel.HasComponent(handlerInterface))
{
IocContainer.Register(Component.For(handlerInterface).ImplementedBy(handlerType));
}
//放入总线中
if (mapDic.Keys.Contains(dataType))
{
if (!mapDic[dataType].Contains(handlerType))
{
mapDic[dataType].Add(handlerType);
}
}
else
{ mapDic[dataType] = new List<Type>() { handlerType }; }
}
//取消注册只是取消EventBus中的事件处理,并不需要处理容器,所以代码相同
public void Unregister<TEventData>(Type handler) where TEventData : IEventData
{
var dataType = typeof(TEventData);
Unregister(dataType, handler);
} public void Unregister(Type eventType, Type handler)
{ if (mapDic.Keys.Contains(eventType))
{
if (mapDic[eventType].Contains(handler))
{
mapDic[eventType].Remove(handler);
}
}
}
/// <summary>
/// 触发调用处理事件
/// </summary>
/// <typeparam name="TEventData"></typeparam>
/// <param name="eventData"></param>
public void Trigger<TEventData>(TEventData eventData) where TEventData : IEventData
{
// var dataType = typeof(TEventData);
var dataType = eventData.GetType();
var handlerTypes = mapDic[dataType];
foreach (var handlerType in handlerTypes)
{ //从Ioc容器中获取所有的实例
var handlerInterface = handlerType.GetInterface("IEventHandler`1");
var eventHandlers = IocContainer.ResolveAll(handlerInterface); //循环遍历,仅当解析的实例类型与映射字典中事件处理类型一致时,才触发事件
foreach (var eventHandler in eventHandlers)
{
if (eventHandler.GetType() == handlerType)
{
var handler = eventHandler as IEventHandler<TEventData>;
handler?.Handle(eventData);
}
} }
}
} }
IOC(第二种)
using Castle.MicroKernel.Registration;
using Castle.Windsor;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace EventBus
{
public class IOCEventBus : IEventBus
{
private IOCEventBus()
{
IocContainer = new WindsorContainer();
mapDic = new ConcurrentDictionary<Type, List<Type>>(); }
//EventBus单例模式
public static IOCEventBus Default = new IOCEventBus();
public IWindsorContainer IocContainer { get; private set; }
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 dataType, Type handlerType)
{
//注册IEventHandler<T>到IOC容器
var handlerInterface = handlerType.GetInterface("IEventHandler`1");
if (!IocContainer.Kernel.HasComponent(handlerInterface))
{
IocContainer.Register(
Component.For(handlerInterface, handlerType));
}
//放入总线中
if (mapDic.Keys.Contains(dataType))
{
if (!mapDic[dataType].Contains(handlerType))
{
mapDic[dataType].Add(handlerType);
}
}
else
{
mapDic[dataType] = new List<Type>() { handlerType };
}
}
//取消注册只是取消EventBus中的事件处理,并不需要处理容器,所以代码相同
public void Unregister<TEventData>(Type handler) where TEventData : IEventData
{
var dataType = typeof(TEventData);
Unregister(dataType, handler);
}
public void Unregister(Type eventType, Type handler)
{
if (mapDic.Keys.Contains(eventType))
{
if (mapDic[eventType].Contains(handler))
{
mapDic[eventType].Remove(handler);
}
}
}
/// <summary>
/// 触发调用处理事件
/// </summary>
/// <typeparam name="TEventData"></typeparam>
/// <param name="eventData"></param>
public void Trigger<TEventData>(TEventData eventData) where TEventData : IEventData
{
// var dataType = typeof(TEventData);
var dataType = eventData.GetType();
var handlerTypes = mapDic[dataType];
foreach (var handlerType in handlerTypes)
{
var eventHandler = IocContainer.Resolve(handlerType);
var handler = eventHandler as IEventHandler<TEventData>;
handler.Handle(eventData);
}
}
}
}
上面的代码都是可以正常运行,其实上面的两种方式只是代码上书写的区别,主要是注入的方式不同,导致代码书写的方式不同

第一种方式Tigger的时候比多,效率比较低,第二种方式代码较少,同时效率较高,但是向容器注入的类型比较多。Component.For方法上的使用还是很有意思的,第二种种方式直接向For的方法中传入了接口和类两个参数,而这个方法的作用,就是为传入的类型创建注入实例的,所以会在容器中注入接口和类。所以在后面Trigger的时候可以直接通过类的类型直接获取到实例。For方法最终在源码中会调用AddService

上面的事件总线只是简单实现了基本的功能,基本上就是ABP事件总线的最最简单的模型,到此为止,事件总线的学习结束。
ABP之事件总线(5)的更多相关文章
- ABP之事件总线(4)
在上一篇的随笔中,我们已经初步完成了EventBus,但是EventBus中还有诸多的问题存在,那么到底有什么问题呢,接下来我们需要看一看ABP中的源码是如何定义EventBus的. 1.第一个点 在 ...
- 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 ...
随机推荐
- docker部署maven私有仓库 nexus3
docker pull sonatype/nexus3: docker run -d --name nexus3.x --network host -v /volume-data/nexus3/nex ...
- Kubernetes的ConfigMap解析
ConfigMap功能在Kubernetes1.2版本的时候就有了,许多应用程序会从配置文件.命令行参数或环境变量中读取配置信息.这些配置信息需要与docker image解耦,你总不能每修改一个配置 ...
- 最好的Python机器学习库
参考链接:http://www.csdn.net/article/2015-12-10/2826435
- 在 Redis 上实现的分布式锁
由于近排很忙,忙各种事情,还有工作上的项目,已经超过一个月没写博客了,确实有点惭愧啊,没能每天或者至少每周坚持写一篇博客.这一个月里面接触到很多新知识,同时也遇到很多技术上的难点,在这我将对每一个有用 ...
- docker的swarm介绍
转载自:https://blog.csdn.net/karamos/article/details/80132082 另外一篇:https://www.jianshu.com/p/9eb9995884 ...
- 十大高明的Google搜索技巧
WHY 对于google检索,有时需要技巧会得到更好的检索结果,不用简单输入关键字检索后,一个个去浏览.对于这些技巧,基本都知道,但是如果不经常用,总是忘了,又得重新搜索下具体使用方法,这里就把它放到 ...
- 【Android】开源项目UniversalImageLoader及开源框架ImageLoader
UniversalImageLoader 简单来说就是用于加载图片的一个开源项目,在其项目介绍中是这么写的 支持多线程图片加载 提供丰富的细节配置,比如线程池大小,HTPP请求项,内存和磁盘缓存,图片 ...
- Go Revel - Testing(测试模块)
revel提供了一个测试框架来方便的为自己的程序编写功能测试用例. 默认创建的应用骨架附带一个简单的测试用例,这里将它作为起点 ##概览 测试保存在`tests`目录: corp/myapp app/ ...
- CAS (15) — CAS 线上环境 Ehcache Replication 的非稳定重现错误 java.util.ConcurrentModificationException
CAS (15) - CAS 线上环境 Ehcache Replication 的非稳定重现错误 摘要 线上环境在 EhCache Replication 过程中出现 java.util.Concur ...
- Opencv Mat运算(转)
一.矩阵Mat I,img,I1,I2,dst,A,B; double k,alpha; Scalar s; //注意Mat的行列号是从0开始的 //定义矩阵a,b,c Mat a,b,c; //生成 ...