ABP之事件总线

Posted 善良的小赵

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ABP之事件总线相关的知识,希望对你有一定的参考价值。

前面已经对Castle Windsor的基本使用进行了学习,有了这个基础,接下来我们将把我们的事件总线再次向ABP中定义的事件总线靠近。从源码中可以知道在ABP中定义了Dictionary,存放三种类型的Factory,然后通过容器的方式实例化相应的handlerfactory。承接前面的随笔,我们为什么要使用IOC?

IOC是用来代替反射的。那么反射在我们EventBus中有什么功能?反射是用来创建handler的实例的。那么我们的容器其实就是用来初始化实例这么一点功能的,所以我们不需要过多的改动我们以前的代码,只需加入容器的注入,同时在初始化的时候将反射的方式改为容器的方式。

IOCEventBus(第一种)

using Castle.MicroKernel.Registration;
using Castle.Windsor;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EventBus
{
    public class IOCEventBus : IEventBus
    {
        private IOCEventBus()
        {
            IocContainer = new WindsorContainer();
            mapDic = new ConcurrentDictionary<Type, List<Type>>();
          
        }
        //EventBus单例模式
        public static IOCEventBus Default = new IOCEventBus();
        public IWindsorContainer IocContainer { get; private set; }
        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 dataType, Type handlerType)
        {
            //注册IEventHandler<T>到IOC容器
            var handlerInterface = handlerType.GetInterface("IEventHandler`1");
            if (!IocContainer.Kernel.HasComponent(handlerInterface))
            {

               IocContainer.Register(Component.For(handlerInterface).ImplementedBy(handlerType));

            }
            //放入总线中
            if (mapDic.Keys.Contains(dataType))
            {
                if (!mapDic[dataType].Contains(handlerType))
                {
                    mapDic[dataType].Add(handlerType);
                }
            }
            else
            {
               
                mapDic[dataType] = new List<Type>() { handlerType };
               
            }
        }
        //取消注册只是取消EventBus中的事件处理,并不需要处理容器,所以代码相同
        public void Unregister<TEventData>(Type handler) where TEventData : IEventData
        {
            var dataType = typeof(TEventData);
            Unregister(dataType, handler);
        }

        public void Unregister(Type eventType, Type handler)
        {

            if (mapDic.Keys.Contains(eventType))
            {
                if (mapDic[eventType].Contains(handler))
                {
                    mapDic[eventType].Remove(handler);
                }
            }
        }
        /// <summary>
        /// 触发调用处理事件
        /// </summary>
        /// <typeparam name="TEventData"></typeparam>
        /// <param name="eventData"></param>
        public void Trigger<TEventData>(TEventData eventData) where TEventData : IEventData
        {
            // var dataType = typeof(TEventData);
            var dataType = eventData.GetType();
            var handlerTypes = mapDic[dataType];
            foreach (var handlerType in handlerTypes)
            {

                //从Ioc容器中获取所有的实例
                var handlerInterface = handlerType.GetInterface("IEventHandler`1");
                var eventHandlers = IocContainer.ResolveAll(handlerInterface);

                //循环遍历,仅当解析的实例类型与映射字典中事件处理类型一致时,才触发事件
                foreach (var eventHandler in eventHandlers)
                {
                    if (eventHandler.GetType() == handlerType)
                    {
                        var handler = eventHandler as IEventHandler<TEventData>;
                        handler?.Handle(eventData);
                    }
                }
           
            }
        }
    }

}

 

IOC(第二种)

using Castle.MicroKernel.Registration;
using Castle.Windsor;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EventBus
{
    public class IOCEventBus : IEventBus
    {
        private IOCEventBus()
        {
            IocContainer = new WindsorContainer();
            mapDic = new ConcurrentDictionary<Type, List<Type>>();
          
        }
        //EventBus单例模式
        public static IOCEventBus Default = new IOCEventBus();
        public IWindsorContainer IocContainer { get; private set; }
        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 dataType, Type handlerType)
        {
            //注册IEventHandler<T>到IOC容器
            var handlerInterface = handlerType.GetInterface("IEventHandler`1");
            if (!IocContainer.Kernel.HasComponent(handlerInterface))
            {

                IocContainer.Register(
                      Component.For(handlerInterface, handlerType));


            }
            //放入总线中
            if (mapDic.Keys.Contains(dataType))
            {
                if (!mapDic[dataType].Contains(handlerType))
                {
                    mapDic[dataType].Add(handlerType);
                }
            }
            else
            {
               
                mapDic[dataType] = new List<Type>() { handlerType };
               
            }
        }
        //取消注册只是取消EventBus中的事件处理,并不需要处理容器,所以代码相同
        public void Unregister<TEventData>(Type handler) where TEventData : IEventData
        {
            var dataType = typeof(TEventData);
            Unregister(dataType, handler);
        }

        public void Unregister(Type eventType, Type handler)
        {

            if (mapDic.Keys.Contains(eventType))
            {
                if (mapDic[eventType].Contains(handler))
                {
                    mapDic[eventType].Remove(handler);
                }
            }
        }
        /// <summary>
        /// 触发调用处理事件
        /// </summary>
        /// <typeparam name="TEventData"></typeparam>
        /// <param name="eventData"></param>
        public void Trigger<TEventData>(TEventData eventData) where TEventData : IEventData
        {
            // var dataType = typeof(TEventData);
            var dataType = eventData.GetType();
            var handlerTypes = mapDic[dataType];
            foreach (var handlerType in handlerTypes)
            {

                var eventHandler = IocContainer.Resolve(handlerType);
                var handler = eventHandler as IEventHandler<TEventData>;
                handler.Handle(eventData);

            }
        }
    }

}

 上面的代码都是可以正常运行,其实上面的两种方式只是代码上书写的区别,主要是注入的方式不同,导致代码书写的方式不同

第一种方式Tigger的时候比多,效率比较低,第二种方式代码较少,同时效率较高,但是向容器注入的类型比较多。Component.For方法上的使用还是很有意思的,第二种种方式直接向For的方法中传入了接口和类两个参数,而这个方法的作用,就是为传入的类型创建注入实例的,所以会在容器中注入接口和类。所以在后面Trigger的时候可以直接通过类的类型直接获取到实例。For方法最终在源码中会调用AddService

上面的事件总线只是简单实现了基本的功能,基本上就是ABP事件总线的最最简单的模型,到此为止,事件总线的学习结束。

 

以上是关于ABP之事件总线的主要内容,如果未能解决你的问题,请参考以下文章

片段实例中带有 Otto 事件总线的 IllegalArgumentException

ABP Framework 5.3.0 版本新增功能和变更说明

ABP Framework 5.0 RC.1 新特性和变更说明

LiveData 源码分析之事件总线 LiveBus 实现

Spark2.1.0之源码分析——事件总线

风险洞察之事件总线的探索与演进