[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样板项目) ...
随机推荐
- Linux: Set OR Change The Library Path
Linux: Set OR Change The Library Path by NIX CRAFT on APRIL 9, 2010 · 3 COMMENTS· LAST UPDATED AUGUS ...
- Base: 一种 Acid 的替代方案
原文链接: BASE: An Acid Alternative Pdf下载链接: Base 数据库 ACID,都不陌生:原子性.一致性.隔离性和持久性,这在单台服务器就能搞定的时代,很容易实现,但是到 ...
- 在VisualStudio中应该使用什么字体
转自:http://blog.csdn.net/bclz_vs/article/details/6607695 字体通常分为几个主要类型 San-Serif:无衬线字体 Serif:有衬线的字体 Mo ...
- Oracle Essbase入门系列(三)
数据库计算 Essbase中单元格的数据可以是外部输入或计算而得,单元格因而分为输入单元格和计算单元格.计算单元格的计算方法可以通过大纲中维度成员的合并计算符和公式脚本定义,此称为大纲计算定义. 例1 ...
- .NET 4.6中的性能改进
.NET 4.6中带来了一些与性能改进相关的CLR特性,这些特性中有一部分将会自动生效,而另外一些特性,例如SIMD与异步本地存储(Async Local Storage)则需要对编写应用的方式进行某 ...
- sql读取xml
DECLARE @ItemMessage XML SET @ItemMessage=cast(N'<?xml version="1.0" encoding="utf ...
- text .global_start 和_start
.text定义一个代码段,这是GCC必须的.global_start和_start代码开始地址定义个标记
- python-根据左右值获取城市区域编码
def get_adcode(city): """ 根据城市获取区域编码 :param city: :return: """ db = db ...
- 配置Pylint for Python3.5
事件的缘由是因为在Ubuntu16.04 下面安装了Visual Studio Code, 再编辑的时候说需要Pylint来检查语法,我系统的默认的Python 版本是python2,而我现在正在学习 ...
- 一个自动备份mysql数据库的bat文件内容
自动备份mysql数据库,并已当前的日期时间为目录 copy过去, xcopy将近15年没有用dos命令,还是这么亲切 另 本方法是备份数据库文件,不是dump导出,然后再计划任务中使用,我用的是wa ...