[Architect] Abp 框架原理解析(2) EventBus
本节目录
原理介绍
事件总线大致原理:
(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的更多相关文章
- [Architect] Abp 框架原理解析(5) UnitOfWork
本节目录 介绍 分析Abp源码 实现UOW 介绍 UOW(全称UnitOfWork)是指工作单元. 在Abp中,工作单元对于仓储和应用服务方法默认开启.并在一次请求中,共享同一个工作单元. 同时在Ab ...
- [Architect] Abp 框架原理解析(4) Validation
本节目录 介绍 DataAnnotations ICustomValidate IShouldNormalize 实现Abp Validation 介绍 Abp中在Application层集成了val ...
- [Architect] Abp 框架原理解析(3) DynamicFilters
本节目录 介绍 定义Filter 设置Filter 这是Abp中多租户.软删除.激活\禁用等如此方便的原因 Install-Package EntityFramework.DynamicFilters ...
- [Architect] Abp 框架原理解析(1) Module
本节目录 Abp介绍 Abp源码分析 代码实现 Abp介绍 学习了一段时间的Abp,领略了一下前辈的架构.总结还是SOLID,降低耦合性. 虽然从架构上说甚至不依赖于DI框架,但实际上在基础框架中还是 ...
- EventBus框架原理解析(结合源代码)(上)
上一篇文章http://blog.csdn.net/crazy__chen/article/details/47425779 和大家一起模仿EventBus的实现机制.和大家一起写出了一个简易的Eve ...
- ABP架构解析
ABP总体介绍 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应 ...
- andorid jar/库源码解析之EventBus
目录:andorid jar/库源码解析 EventBus: 作用: 用于不同Activity,Service等之间传递消息(数据). 栗子: A页面:onCreate定义 EventBus.ge ...
- [EventBus源码解析] 初探EventBus
本期blog作为EventBus(以下简称EB)学习的始动篇,主要记载了EB的功能.优点.使用方法,内容基于github上的README.md与HOWTO.md. 何为EventBus EB实现了An ...
- [Architect] ABP(现代ASP.NET样板开发框架) 翻译
所有翻译文档,将上传word文档至GitHub 本节目录: 简介 代码示例 支持的功能 GitHub 简介 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目) ...
随机推荐
- [C] tcharall(让所有平台支持TCHAR)v1.1。源码托管到github、添加CMake编译配置文件、使用doxygen规范注释
作者:zyl910 v1.1版的改动如下—— 将源码上传到github. 调整目录结构. 添加CMake编译配置文件. 使用doxygen规范注释. 文件清单—— docs\ docs\images\ ...
- 解决genemotion模拟器冲突导致的Android Studio无法启动ADB的问题
首先命令行下运行 adb nodaemon server ./adb nodaemon server (Mac OSX) 如果出现错误: error: could not install *smart ...
- Scala 深入浅出实战经典 第44讲: scala中view bounds代码实例
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...
- python数据结构之图深度优先和广度优先
首先有一个概念:回溯 回溯法(探索与回溯法)是一种选优搜索法,按选优条件向前搜索,以达到目标.但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法 ...
- 文件系统管理 之 Linux 创建文件系统及挂载文件系统流程详解
阅读此文,必须具备知识点:<Linux 查看磁盘分区.文件系统.使用情况的命令和相关工具介绍><实例解说 fdisk 使用方法><合理规划您的硬盘分区><Fe ...
- RabbitMQ学习笔记3-使用topic交换器
topic的路由规则里使用[.]号分隔单词,使用[*]号匹配1个单词,使用[#]匹配多个.和多个*. 在下面的例子中: logger.*可以匹配logger.error和logger.warning, ...
- IOS 开发环境,证书和授权文件等详解
(转自:http://blog.csdn.net/gtncwy/article/details/8617788) 一.成员介绍1. Certification(证书)证书是对电脑开发资格的认证, ...
- Redrain个人维护并使用的DuiLib和UiLib库源代码下载地址
转载请说明原出处:http://blog.csdn.net/zhuhongshu/article/details/40740353,谢谢~~ 首先说明一下Duilib和Uilib的差别:UiLIb是D ...
- Spring3系列7- 自动扫描组件或Bean
Spring3系列7- 自动扫描组件或Bean 一. Spring Auto Scanning Components —— 自动扫描组件 1. Declares Component ...
- URL 学习总结
1.绝对路径(以"/"斜线开头的路径,代表相对于当前Web应用): a)地址给服务器用,web应用名称可以省略. 请求包含:request.getRequestDispatcher ...