本节目录

原理介绍

事件总线大致原理:

(1)       在事件总线内部维护着一个事件与事件处理程序相映射的字典。

(2)       利用反射,事件总线会将实现了IEventHandler的处理程序与相应事件关联到一起,相当于实现了事件处理程序对事件的订阅。

(3)       当发布事件时,事件总线会从字典中找出相应的事件处理程序,然后利用反射去调用事件处理程序中的方法。

Abp源码分析

1.AbpKernelModule的Initialize方法

2.EventBusInstaller的Install方法

3.Kernel_ComponentRegistered

以上将事件注册完成了.

剩下就需要如何触发了.

触发实际上是写在代码里的,最终调用的其实还是EventBus.Trigger()

代码实现

看完Abp的实现,关键点还是反射以及IoC注册对象事件的拦截.

先上实现效果:

    interface IPerson
{
void Say();
}
class Person : IPerson
{
public IEventBus EventBus { get; set; }
public void Say()
{
var str = "Say";
Console.WriteLine(str);
EventBus.Trigger(typeof(SayEventData), this, new SayEventData() { Content = str });
}
}

定义上面需要的EventData,实际这是事件基类.

    [Serializable]
public abstract class EventData : IEventData
{
public DateTime EventTime { get; set; } /// <summary>
/// The object which triggers the event (optional).
/// </summary>
public object EventSource { get; set; } protected EventData()
{
EventTime = DateTime.Now;
}
} public interface IEventData
{
DateTime EventTime { get; set; } object EventSource { get; set; }
}

自定义事件,继承事件基类,可以添加事件需要传递的数据.

    public class SayEventData : EventData
{
public string Content { get; set; }
}

定义IEventHandle,实际这是事件处理程序,一个事件一般对应多个事件处理程序.

  public interface IEventHandler
{ }
public interface IEventHandler<in TEventData> : IEventHandler
{
/// <summary>
/// Handler handles the event by implementing this method.
/// </summary>
/// <param name="eventData">Event data</param>
void HandleEvent(TEventData eventData);
}

自定义的EventHandle,各种事件订阅器.

    public class SayEvent : IEventHandler<SayEventData>
{
public void HandleEvent(SayEventData eventData)
{
Console.WriteLine("进入事件啦:" + eventData.Content);
}
}

事件总线EventBus,管理事件的中心.可以细化接口.

    public interface IEventBus
{
void Register(Type eventType, IEventHandler handler); void Trigger(Type eventType, object eventSource, IEventData eventData);
}

EventBus实现,核心是反射调用事件处理程序.

    public class EventBus : IEventBus
{
public static EventBus Default { get { return DefaultInstance; } }
private static readonly EventBus DefaultInstance = new EventBus();
private readonly Dictionary<Type, List<IEventHandler>> _eventHandlers;
public EventBus()
{
_eventHandlers = new Dictionary<Type, List<IEventHandler>>();
}
public void Register(Type eventType, IEventHandler handler)
{
GetOrCreateHandlerFactories(eventType).Add(handler);
}
private List<IEventHandler> GetOrCreateHandlerFactories(Type eventType)
{
List<IEventHandler> handlers;
if (!_eventHandlers.TryGetValue(eventType, out handlers))
{
_eventHandlers[eventType] = handlers = new List<IEventHandler>();
}
return handlers;
}
public void Trigger(Type eventType, object eventSource, IEventData eventData)
{
eventData.EventSource = eventSource;
var handles = GetOrCreateHandlerFactories(eventType);
if (handles.Count > 0)
{
foreach (var eventHandler in handles)
{
if (eventHandler == null)
{
throw new Exception("Registered event handler for event type " + eventType.Name + " does not implement IEventHandler<" + eventType.Name + "> interface!");
}
//eventHandler.
var handlerType = typeof(IEventHandler<>).MakeGenericType(eventType); handlerType
.GetMethod("HandleEvent", BindingFlags.Public | BindingFlags.Instance, null, new[] { eventType }, null)
.Invoke(eventHandler, new object[] { eventData });
}
}
}
}

执行,来测试是否通了.

        private static IEventBus _eventBus;
static void Main(string[] args)
{
var container = IocManager.Instance.IocContainer;
container.Register(Component.For<IEventBus>().Instance(EventBus.Default));
_eventBus = container.Resolve<IEventBus>();
container.Kernel.ComponentRegistered += Kernel_ComponentRegistered; //在Abp中,由于注册了所有ITransientDependency,所以这2个不需要手动注册
container.Register(Component.For<Person, IPerson>());
container.Register(Component.For<IEventHandler<SayEventData>, SayEvent>()); container.Resolve<IPerson>().Say();
Console.ReadKey();
}

  

注册事件的绑定

private static void Kernel_ComponentRegistered(string key, IHandler handler)
{
if (!typeof(IEventHandler).IsAssignableFrom(handler.ComponentModel.Implementation))
{
return;
} var interfaces = handler.ComponentModel.Implementation.GetInterfaces();
foreach (var @interface in interfaces)
{
if (!typeof(IEventHandler).IsAssignableFrom(@interface))
{
continue;
} var genericArgs = @interface.GetGenericArguments();
if (genericArgs.Length == 1)
{
//_eventBus.Register(genericArgs[0], handler.ComponentModel.Implementation.CreateInstance<IEventHandler>());
_eventBus.Register(genericArgs[0], (IEventHandler)IocManager.Instance.IocContainer.Resolve(handler.ComponentModel.Implementation));
}
}
}

至此,事件成功执行

本文地址:http://www.cnblogs.com/neverc/p/5254859.html

[Architect] Abp 框架原理解析(2) EventBus的更多相关文章

  1. [Architect] Abp 框架原理解析(5) UnitOfWork

    本节目录 介绍 分析Abp源码 实现UOW 介绍 UOW(全称UnitOfWork)是指工作单元. 在Abp中,工作单元对于仓储和应用服务方法默认开启.并在一次请求中,共享同一个工作单元. 同时在Ab ...

  2. [Architect] Abp 框架原理解析(4) Validation

    本节目录 介绍 DataAnnotations ICustomValidate IShouldNormalize 实现Abp Validation 介绍 Abp中在Application层集成了val ...

  3. [Architect] Abp 框架原理解析(3) DynamicFilters

    本节目录 介绍 定义Filter 设置Filter 这是Abp中多租户.软删除.激活\禁用等如此方便的原因 Install-Package EntityFramework.DynamicFilters ...

  4. [Architect] Abp 框架原理解析(1) Module

    本节目录 Abp介绍 Abp源码分析 代码实现 Abp介绍 学习了一段时间的Abp,领略了一下前辈的架构.总结还是SOLID,降低耦合性. 虽然从架构上说甚至不依赖于DI框架,但实际上在基础框架中还是 ...

  5. EventBus框架原理解析(结合源代码)(上)

    上一篇文章http://blog.csdn.net/crazy__chen/article/details/47425779 和大家一起模仿EventBus的实现机制.和大家一起写出了一个简易的Eve ...

  6. ABP架构解析

    ABP总体介绍 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应 ...

  7. andorid jar/库源码解析之EventBus

    目录:andorid jar/库源码解析 EventBus: 作用: 用于不同Activity,Service等之间传递消息(数据). 栗子: A页面:onCreate定义   EventBus.ge ...

  8. [EventBus源码解析] 初探EventBus

    本期blog作为EventBus(以下简称EB)学习的始动篇,主要记载了EB的功能.优点.使用方法,内容基于github上的README.md与HOWTO.md. 何为EventBus EB实现了An ...

  9. [Architect] ABP(现代ASP.NET样板开发框架) 翻译

    所有翻译文档,将上传word文档至GitHub 本节目录: 简介 代码示例 支持的功能 GitHub 简介 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目) ...

随机推荐

  1. ELK——Logstash 2.2 date 插件【翻译+实践】

    官网地址 本文内容 语法 测试数据 可配置选项 参考资料 date 插件是日期插件,这个插件,常用而重要. 如果不用 date 插件,那么 Logstash 将处理时间作为时间戳.时间戳字段是 Log ...

  2. C#删除字符串最后一个字符的几种方法

    字符串:string s = "1,2,3,4,5,"目标:删除最后一个 "," 方法:1.用的最多的是Substring,这个也是我一直用的s = s.Sub ...

  3. Ubunbu新建的用户使用SecureCrt无法Table补全、无法高亮

    Check 两个地方: 1.  确保/etc/passwd中配置有/bin/bash (这个是用来控制补全). 2. 在~/.bashrc中配置, export TERM=linux (这个是用来控制 ...

  4. 2. MongoDB基本操作 —— 用Mongo.exe操作数据库增删改查

    一.开篇 传统的关系数据库一般由数据库(database).表(table).记录(record)三个层次概念组成,MongoDB是由数据库(database).集合(collection).文档对象 ...

  5. [原]常用sqlserver数据库使用sql语句

    1.表结构文档生成查询语句: SELECT 架构名 Then s.[name] Else '' End, 表名 Then D.name Else '' End, 表说明 Then isnull(F.v ...

  6. HBase修改压缩格式及Snappy压缩实测分享

    一.要点 有关Snappy的相关介绍可参看Hadoop压缩-SNAPPY算法,如果想安装Snappy,可以参看Hadoop HBase 配置 安装 Snappy 终极教程. 1. HBase修改Tab ...

  7. Spring源码追踪4——SpringMVC View解析

    这次的议题是返回json和返回普通view经过的路线差异. ---------------------------------------------------------------------- ...

  8. 安卓Android面试题大全

    56个问题都是经常用到的,可以深入研究下,也是必须掌握的开发必备知识. 安卓Android面试题汇总 搜集了一些Android面试题目,供将要面试或者正在面试的朋友参考. 1, 谈谈你对Activit ...

  9. 数据人员Sql必会列转行

    列转行上一篇博客已经介绍过了. 下面介绍一下行转列的实现 假设我们有一个数据表: CREATE TABLE row_to_line ( ) NOT NULL, -- 学生名称 yingyu integ ...

  10. 导出程序界面(UI)到图片

    无意间看到这个需求,查阅了相关文章,有两篇不错的博客给出了解决方案,地址如下: 1.在WPF程序中将控件所呈现的内容保存成图像 2.随心所欲导出你的 UI 界面到 PDF 文件 主要使用的接口: Si ...