ABP EventBus(事件总线)
事件总线就是订阅/发布模式的一种实现 事件总线就是为了降低耦合
1.比如在winform中 到处都是事件

触发事件的对象 sender
事件的数据 e
事件的处理逻辑 方法体
通过EventBus实现事件对象和处理逻辑的解耦

1.抽离事件对象 发生时间的事件 触发事件的对象源(可选)
//
// 摘要:
// Defines interface for all Event data classes.
public interface IEventData
{
//
// 摘要:
// The time when the event occured.
DateTime EventTime { get; set; }
//
// 摘要:
// The object which triggers the event (optional).
object EventSource { get; set; }
2.抽离事件的处理对象
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);
}
3.所有EventData跟EventHandler不再耦合 全都跟EventBus进行通信
在EventBus中有一个字典进行存放 EventData类型跟需要触发的Handler对象
这里的Type就是EventData List<IEventHandlerFactory>>就是存放处理当前EventData的多个Handler
private readonly ConcurrentDictionary<Type, List<IEventHandlerFactory>> _handlerFactories;
4.ABP的EventBus封装的比较高深 自己来个简洁版 思想是一样的(这里还存在很多问题 比如并发 往字典存放数据没有加锁等问题 具体的看ABP)
ABP初始化的时候会把所有的EventData和EventHandler对应存放到字典中 也可以通过Unregister移除某一个Handler
public class EventBus : IEventBus
{
public EventBus()
{
mapDic = new ConcurrentDictionary<Type, List<Type>>();
}
//EventBus单例模式
public static EventBus Default = new EventBus();
//存储EventData和EventHandle的映射关系(没有存放handler的实例而是存放metaData,然后通过反射调用)
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 eventType, Type handlerType)
{
if (mapDic.Keys.Contains(eventType))
{
if (!mapDic[eventType].Contains(handlerType))
{
mapDic[eventType].Add(handlerType);
}
}
else
{
mapDic[eventType] = new List<Type>() { handlerType };
}
} public void Unregister<TEventData>(Type handler) where TEventData : IEventData
{
var dataType = typeof(TEventData);
Unregister(dataType, handler);
} public void Unregister(Type eventType, Type handlerType)
{
if (mapDic.Keys.Contains(eventType))
{
if (mapDic[eventType].Contains(handlerType))
{
mapDic[eventType].Remove(handlerType);
}
}
} public void Trigger<TEventData>(TEventData eventData) where TEventData : IEventData
{
var dataType = eventData.GetType();
//获取当前的EventData绑定的所有Handler
var handlerTypes = mapDic[dataType];
foreach (var handlerType in handlerTypes)
{
var methodInfo = handlerType.GetMethod("EventHandle");
if (methodInfo != null)
{
// var handler = Assembly.GetExecutingAssembly().CreateInstance(handlerType.FullName);
var handler = Activator.CreateInstance(handlerType);
//执行所有的Handler方法
methodInfo.Invoke(handler, new object[] { eventData });
}
}
}
}
提供了EventData和Handler的绑定 也可以移除指定的Handler
通过调用.Trigger() 然后当前的EventData类型在字典中找到当前类型的所有Handler 执行所有Handler的处理方法
事件总线通过 EventBusInstaller 来注册 EventBus 和监听事件。 每当IocContainer注册一个类型后 会判断当前类型是否实现IEventHandler 获取具体的EventData类型在EventBus上进行注册
private void Kernel_ComponentRegistered(string key, IHandler handler)
{
/* This code checks if registering component implements any IEventHandler<TEventData> interface, if yes,
* gets all event handler interfaces and registers type to Event Bus for each handling event.
*/
if (!typeof(IEventHandler).GetTypeInfo().IsAssignableFrom(handler.ComponentModel.Implementation))
{
return;
} var interfaces = handler.ComponentModel.Implementation.GetTypeInfo().GetInterfaces();
foreach (var @interface in interfaces)
{
if (!typeof(IEventHandler).GetTypeInfo().IsAssignableFrom(@interface))
{
continue;
} var genericArgs = @interface.GetGenericArguments();
if (genericArgs.Length == )
{
_eventBus.Register(genericArgs[], new IocHandlerFactory(_iocResolver, handler.ComponentModel.Implementation));
}
}
}
在ABP中使用EventBus
1.定义自己的数据对象
public class MyEventData : EventData
{
public string Name { get; set; }
}
2.定义自己的处理事件Handler
public class MyEventHandler : IEventHandler<MyEventData>, ITransientDependency
{
public ILogger Logger { set; get; }
public MyEventHandler()
{
Logger = NullLogger.Instance;
}
public void HandleEvent(MyEventData eventData)
{
Logger.Info($"这是{eventData.Name}自定义的HandEvent处理事件");
}
}
3.通过属性注入 或者构造函数注入 或者直接用静态实例
public class TaskAppService : ApplicationService
{
public IEventBus EventBus { get; set; } public TaskAppService()
{
EventBus = NullEventBus.Instance;
} public void CompleteTask(CompleteTaskInput input)
{
EventBus.Trigger(new MyEventData {Name= "abc123"});
}
}
EventBus.Default.Trigger(new MyEventData {Name= "abc123"});
https://www.cnblogs.com/myzony/p/9413351.html
ABP EventBus(事件总线)的更多相关文章
- Guava - EventBus(事件总线)
Guava在guava-libraries中为我们提供了事件总线EventBus库,它是事件发布订阅模式的实现,让我们能在领域驱动设计(DDD)中以事件的弱引用本质对我们的模块和领域边界很好的解耦设计 ...
- EventBus(事件总线)
EventBus(事件总线) Guava在guava-libraries中为我们提供了事件总线EventBus库,它是事件发布订阅模式的实现,让我们能在领域驱动设计(DDD)中以事件的弱引用本质对我们 ...
- dhroid - eventbus 事件总线
你听过onClick 事件,onItemClick 事件,事件总线不一定听过吧, eventbus 事件总线也是一个编程思想,为什么要设计EventBus了,因为他是领域驱动设计中比不可少的模块,它承 ...
- EventBus事件总线
EventBus事件总线的使用-自己实现事件总线 在C#中,我们可以在一个类中定义自己的事件,而其他的类可以订阅该事件,当某些事情发生时,可以通知到该类.这对于桌面应用或者独立的windows服务 ...
- ABP之事件总线(5)
前面已经对Castle Windsor的基本使用进行了学习,有了这个基础,接下来我们将把我们的事件总线再次向ABP中定义的事件总线靠近.从源码中可以知道在ABP中定义了Dictionary,存放三种类 ...
- ABP之事件总线(4)
在上一篇的随笔中,我们已经初步完成了EventBus,但是EventBus中还有诸多的问题存在,那么到底有什么问题呢,接下来我们需要看一看ABP中的源码是如何定义EventBus的. 1.第一个点 在 ...
- ABP之事件总线(3)
承接上一篇时间总线的学习,在上一篇中我们实现了取消显式注册事件的方式,采用使用反射的方式.这样的好处可以解除Publisher和Scriber的显式依赖,但是问题又来了,因为我们只有Publisher ...
- EventBus 事件总线 案例
简介 地址:https://github.com/greenrobot/EventBus EventBus是一个[发布 / 订阅]的事件总线.简单点说,就是两人[约定]好怎么通信,一人发布消息,另外一 ...
- C#总结(六)EventBus事件总线的使用-自己实现事件总线
在C#中,我们可以在一个类中定义自己的事件,而其他的类可以订阅该事件,当某些事情发生时,可以通知到该类.这对于桌面应用或者独立的windows服务来说是非常有用的.但对于一个web应用来说是有点问题的 ...
- Android 开发 框架系列 EventBus 事件总线
介绍 GitHub:https://github.com/greenrobot/EventBus 先聊聊EventBus 线程总线是干什么的,使用环境,优点.缺点. 干什么的? 一句话,简单统一数据传 ...
随机推荐
- DetNet: A Backbone network for Object Detection 笔记
1 前言 主要贡献: (1)第一个分析微调传统ImageNet预训练模型应用于目标检测器的固有缺点 (2)提出一个名为DetNet的新的骨干结构,它通过保持空间分辨率和扩大感受野的方式来专门设计用于目 ...
- 201808_summary
@Consumes @Produces分别表示入参和出参数吗 可以这样讲.但是不是很到位.是限定作用,类似于filterconsumes: 指定处理请求的提交内容类型(Content-Type),例如 ...
- python小程序--Three(三级菜单)
#!/usr/bin/env python # _*_ coding:utf8 _*_ data = { "山东省":{ "滨州市":{"惠民县&qu ...
- vue评论显示隐藏,JavaScript显示关闭
<template> <div id="vue_det"> <h1>{{details()}}</h1> <div>{{ ...
- (.NET高级课程笔记)Lambd、Linq总结
知识总结 1.委托简介:委托是一种类型,可以写在类里,也可以写在类外面,级别和类一样高. 2.匿名方法.匿名类 3.Lambda表达式:goes to 4.系统自带委托:Func/Action 5.扩 ...
- Android -- 带你从源码角度领悟Dagger2入门到放弃(三)
1, 前面两篇文章我们知道了怎么使用常用的四种标签,现在我们结合我们自己的项目中去简单的使用 在我们搭建项目的时候,一般会创建自己的Application,在里面进行一些初始化如一些第三方的Green ...
- 简单的Json数据
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <hea ...
- 记录心得-IntelliJ iDea 创建一个maven管理的的javaweb项目
熟能生巧,还是记录一下吧~ 开始! 第一步:File--New--Project--Maven--Create from archetype--maven-archetype-webapp 第二步:解 ...
- zimbra填坑记录
邮件服务器上架,问题记录. 1.DNS解析设置,zimbra收发邮件均使用统一域名,mail.xxxx.com.cn,因此在做SMTP,POP,MX记录时均应指向此域名. 2.实际上架内部网络和安装所 ...
- 日常开发工作常用linux命令
:wq 保存退出 :q! 强制退出 vi 查看 vim 编辑 rpm -qa|grep jdk 命令查看当前的jdk情况 yum -y remove java java-1.7.0-openjdk* ...