ABP EventBus(事件总线)

Stella981
• 阅读 875

事件总线就是订阅/发布模式的一种实现    事件总线就是为了降低耦合

1.比如在winform中  到处都是事件 

ABP EventBus(事件总线)

触发事件的对象  sender

事件的数据    e

事件的处理逻辑  方法体

通过EventBus实现事件对象和处理逻辑的解耦

ABP 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>就是存放处理当前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 == 1)
                {
                    _eventBus.Register(genericArgs[0], 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

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
Apache Synapse 远程代码执行漏洞(CVE
!(https://oscimg.oschina.net/oscnet/435fc4cde65d4aee9a2efca3080cb89e.png)0x00事件背景ApacheSynapse是一个简单、轻量级的高性能企业服务总线(ESB),它是在ApacheSoftwareFoun
Stella981 Stella981
3年前
Guava — EventBus
Guava提供了事件总线的一个实现方案EventBus。它是事件发布订阅模式的实现,观察者模式。Guava为我们提供了同步实现EventBus和异步实现AsyncEventBus两个事件总线,他们都不是单例的eventBus.post(1);eventBus.post(1L);post方法,直接发布事件订阅者需要注册进来,ev
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Stella981 Stella981
3年前
Android面试之EventBus
简介众所周知,EventBus是一款用在Android开发中的发布/订阅事件总线框架,基于观察者模式,将事件的接收者和发送者分开,简化了组件之间的通信操作,使用简单、效率高、体积小!EventBus使用了典型的发布/订阅事件模式,下面是EventBus官方给出的原理示意图。!在这里插入图片描述(https://oscimg.o
Stella981 Stella981
3年前
Noark入门之异步事件
引入异步事件主要是为了各模块的解耦,每当完成一个动作时,向系统发布一个事件,由关心的模块自己监听处理,可选择同步处理,异步处理,延迟处理。何时发布事件,当其他模块关心此动作时<br比如获得道具时,任务系统模块要判定完成进度,BI模块需要上报等等都可以监听此事件,已达模块解耦0x00事件源一个实现xyz.noark.core.event
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这