前面已经对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)的更多相关文章

  1. ABP之事件总线(4)

    在上一篇的随笔中,我们已经初步完成了EventBus,但是EventBus中还有诸多的问题存在,那么到底有什么问题呢,接下来我们需要看一看ABP中的源码是如何定义EventBus的. 1.第一个点 在 ...

  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. android ndk-build 编译静态库libxx.a 以及Android studio openssl 静态库配置(cmake)

    android ndk-build 编译静态库libxx.a 需求场景: 目前有安卓编码好的现在的openssl的两个.a,我们需要调用openssl的函数,并把功能再封装成.a; 这样使用时,在an ...

  2. SpringBoot使用Mybatis注解开发教程-分页-动态sql

    代码示例可以参考个人GitHub项目kingboy-springboot-data 一.环境配置 1.引入mybatis依赖 compile( //SpringMVC 'org.springframe ...

  3. 用ctrl+鼠标滚动调节字体大小

    如此设置之后,按住ctrl+鼠标滚动,可以放大和变小代码的字号.

  4. 前后分离模型之封装 Api 调用

    Ajax 和异步处理 调用 API 访问数据采用的 Ajax 方式,这是一个异步过程,异步过程最基本的处理方式是事件或回调,其实这两种处理方式实现原理差不多,都需要在调用异步过程的时候传入一个在异步过 ...

  5. javascript回调函数笔记

    来源于:https://github.com/useaname/blog-study 在Javascript中,函数是第一类对象.意味函数可以像对象一样按照第一类被管理使用.回调函数是从一个叫函数式编 ...

  6. mysql数据库分区功能及实例详解

    分区听起来怎么感觉是硬盘呀,对没错除了硬盘可以分区数据库现在也支持分区了,分区可以解决大数据量的处理问题,下面一起来看一个mysql数据库分区功能及实例详解   一,什么是数据库分区 前段时间写过一篇 ...

  7. 11G新特性 -- ASM的兼容性

    Oracle 11g中,asm同时支持10g和11g数据库.但是asm的版本不能低于数据库的版本. 与兼容性现相关的两个参数: ·compatible.rdbms 支持的最低版本的oracle数据库版 ...

  8. List 比较大小

    List<Player> lst = new List<Player>(); lst.Add()); lst.Add()); lst.Add()); lst.Add()); l ...

  9. Socket网络编程--小小网盘程序(5)

    各位好呀!这一小节应该就是这个小小网盘程序的最后一小节了,这一节将实现最后的三个功能,即列出用户在服务器中的文件列表,还有删除用户在服务器中的文件,最后的可以共享文件给好友. 列出用户在服务器中的文件 ...

  10. ABAP 内表(internal table) 标题行(header line) 工作区(work area) 简介 - [SAP]

    刚开始学ABAP的时候,学到iternal table时,感觉一阵混乱.搞不清楚什么是work area,什么是header line,以及occurs是干什么用的.今天终于差不多搞明白了(我还是太弱 ...