ABP event bus (5)

The basic use of Castle Windsor has been learned before. With this foundation, we will move our event bus closer to the event bus defined in ABP again. From the source code, it can be known that Dictionary is defined in ABP, stores three types of Factory, and then instantiates the corresponding handlerfactory through the container. Continuing the previous essay, why should we use IOC?

IOC is used in place of reflection. So what is the function of reflection in our EventBus? Reflection is used to create instances of handlers. Then our container is actually used to initialize the instance, so we don't need to change our previous code too much, just add the injection of the container, and change the reflection method to the container method during initialization.

IOCEventBus (the first)

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
        {
            // Store data to 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));

            }
             // Put it into the bus 
            if (mapDic.Keys.Contains(dataType))
            {
                if (!mapDic[dataType].Contains(handlerType))
                {
                    mapDic[dataType].Add(handlerType);
                }
            }
            else
            {
               
                mapDic[dataType] = new List<Type>() { handlerType };
               
            }
        }
        // Unregistering only cancels the event processing in EventBus, and does not need to handle the container, so the code is the same 
        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)
            {

                // Get all instances from the Ioc container 
                var handlerInterface = handlerType.GetInterface( " IEventHandler`1 " );
                 var eventHandlers = IocContainer.ResolveAll(handlerInterface);

                // Loop traversal, only when the parsed instance type is consistent with the event processing type in the mapping dictionary, trigger the event 
                foreach ( var eventHandler in eventHandlers)
                {
                    if (eventHandler.GetType() == handlerType)
                    {
                        var handler = eventHandler as IEventHandler<TEventData>;
                        handler?.Handle(eventData);
                    }
                }
           
            }
        }
    }

}

 

IOC (second type)

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
        {
            // Store data to 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));


            }
            // Put it into the bus 
            if (mapDic.Keys.Contains(dataType))
            {
                if (!mapDic[dataType].Contains(handlerType))
                {
                    mapDic[dataType].Add(handlerType);
                }
            }
            else
            {
               
                mapDic[dataType] = new List<Type>() { handlerType };
               
            }
        }
        // Unregistering only cancels the event processing in EventBus, and does not need to handle the container, so the code is the same 
        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);

            }
        }
    }

}

 The above code can run normally. In fact, the above two methods are only the difference in writing the code. The main difference is the way of injection, which leads to different ways of writing the code.

The first way Tigger has more time and lower efficiency. The second way has less code and higher efficiency, but more types are injected into the container. The use of the Component.For method is still very interesting. The second method directly passes in two parameters, the interface and the class, to the For method. The function of this method is to create an injection instance for the incoming type, so Interfaces and classes are injected into the container. Therefore, when Trigger is used later, the instance can be obtained directly through the type of the class. The For method will eventually call AddService in the source code

The above event bus simply implements the basic functions, which is basically the simplest model of the ABP event bus. So far, the learning of the event bus is over.

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325946300&siteId=291194637