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 ...
随机推荐
- JVM内存区域的划分(内存结构或者内存模型)
JVM内存区域的划分(内存结构或者内存模型) 运行时数据区域: 根据 JVM 规范,JVM 内存共分为虚拟机栈.堆.方法区.程序计数器.本地方法栈五个部分. 程序计数器(线程私有): 是当前线程所 ...
- HTML解析库Gumbo简单使用记录
目录 Gumbo简介 使用记录 1.GumboNode的类型 2.简单的使用 Gumbo简介 Gumbo是谷歌开源的一个纯C编写的HTML解析库,性能很好,就是用起来比较麻烦. github地址htt ...
- 基于Ubuntu部署 memcached 服务
系统要求:Ubuntu 16.04.1 LTS 64 位操作系统 安装并启动 memcached 服务 安装 memcached 使用apt-get安装 memcached sudo apt-get ...
- 小型IT部门建设之我见
关于IT团队建设,一般的原则是四大块组成: 1:业务分析师,对接业务部门,把业务需求转变成技术需求 专注于BRS( Business Requirement Speci ...
- C#-MVC开发微信应用(4)--微信门户菜单的管理操作
最近对微信接口进行深入的研究,通过把底层接口一步步进行封装后,逐步升级到自动化配置.自动化应答,以及后台处理界面的优化和完善上,力求搭建一个较为完善.适用的微信门户应用管理系统. 在微信门户系统里面, ...
- 使用VisualSVN Server搭建SVNserver (Windows环境为例)
使用 VisualSVN Server来实现主要的 SVN功能则要比使用原始的 SVN和Apache相配合来实现源代码的 SVN管理简单的多,下面就看看详细的说明. VisualSVN Server的 ...
- Socket网络编程--聊天程序(9)
这一节应该是聊天程序的最后一节了,现在回顾我们的聊天程序,看起来还有很多功能没有实现,但是不管怎么说,都还是不错的.这一节我们将讲多服务器问题(高大上的说法就是负载问题了.)至于聊天程序的文件发送(也 ...
- 【Java】加载驱动方法
1.Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); 2. DriverManager.register ...
- pandas 学习总结
pandas 学习总结 作者:csj 更新时间:2018.04.02 shenzhen email:59888745@qq.com home: http://www.cnblogs.com/csj0 ...
- Go语言实践_实现一(服务器端)对多(客户端)在线聊天室
一.目的 运用Go语言中的goroutine和通道实现一个简单的一个服务器端对多个客户端的在线聊天 软件环境:Goland,Go1.9 代码仓库链接 二.设计思路 与一对一的设计思路类似,就是加了个线 ...