zoukankan      html  css  js  c++  java
  • ABP文档笔记

    文档:

    EventBus(事件总线)

    EventBus是一个单例对象,被所有类触发事件或处理事件时共享。

    IEventBusConfiguration在应用启动时加载(by AbpCoreInstaller),依据它的配置决定 是所有IWindsorContainer实例共享同一条事件总线(EventBus.Default),还是每个IWindsorContainer实例创建一个自己的单例。默认使用EventBus.Default。

    因为在应用中IocManager使用单例,IIocManager.IocContainer也是单一的,所以事件总线使用的就是EventBus.Default。

    注入 IEventBus

    使用属性注入模式:

    public class TaskAppService : ApplicationService
    {
        public IEventBus EventBus { get; set; }
    
        public TaskAppService()
        {
            EventBus = NullEventBus.Instance;
        }
    }
    

    直接使用默认实例

    如果你不能注入它,可以直接使用EventBus.Default。使用方式如下所示:

    EventBus.Default.Trigger(...); //trigger an event
    

    但就如同不推荐使用IocManager.Instance一样,在任何可能的地方都不建议直接使用EventBus.Default,因为它难于单元测试。

    定义事件

    事件定义,继承EventData

    在触发一个事件前,你首先要定义它,通过一个继承自EventData的类来表现一个事件。

    假设当一个任务完成后我们想触发一个事件:

    public class TaskCompletedEventData : EventData
    {
        public int TaskId { get; set; }
    }
    

    这个类包含处理事件类所需要的属性,EventData类定义了EventSource(事件源,哪个对象触发了事件)和EventTime(何时触发的)属性。

    泛型的事件定义,使用IEventDataWithInheritableGenericArgument

    public class EntityEventData<TEntity> : EventData , IEventDataWithInheritableGenericArgument
    {
        /// <summary>
        /// Related entity with this event.
        /// </summary>
        public TEntity Entity { get; private set; }
    
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="entity">Related entity with this event</param>
        public EntityEventData(TEntity entity)
        {
            Entity = entity;
        }
    
        public virtual object[] GetConstructorArgs()
        {
            return new object[] { Entity };
        }
    }
    

    ABP框架预定义的事件

    异常处理事件

    命名空间Event.Bus.Exceptions中定义了ExceptionData 和 AbpHandledExceptionData,当ABP自动处理任何异常时,会触发后者。

    实体修改事件

    命名空间Abp.Events.Bus.Entities中为实体修改提供了泛型的事件:EntityCreationEventData、EntityCreatedEventData、EntityUpdatingEventData、EntityUpdateEventData、EntityDeletingEventData和EntityDeletedEventData,同样也有EntityChangingEventData和EntityChangedEventData

    “ing”事件(例如EntityUpdating)在保存修改(SaveChanges)前触发,所以你可以在这些事件里,通过抛出异常,促使工作单元回滚,阻止操作)。“ed”事件(例如EntityUpdated)在保存修改之后被触发,也就没有机会让工作单元回滚了。

    触发事件

    简单例子

    public class TaskAppService : ApplicationService
    {
    	public IEventBus EventBus { get; set; }
    
    	public TaskAppService()
    	{
    		EventBus = NullEventBus.Instance;
    	}
    
    	public void CompleteTask(CompleteTaskInput input)
    	{
    		//TODO: complete the task on database...
    		EventBus.Trigger(new TaskCompletedEventData {TaskId = 42});
    	}
    }
    

    Trigger方法有几个重载:

    EventBus.Trigger<TaskCompletedEventData>(new TaskCompletedEventData { TaskId = 42 }); //Explicitly declare generic argument
    EventBus.Trigger(this, new TaskCompletedEventData { TaskId = 42 }); //Set 'event source' as 'this'
    EventBus.Trigger(typeof(TaskCompletedEventData), this, new TaskCompletedEventData { TaskId = 42 }); //Call non-generic version (first argument is the type of the event class)
    

    实体修改时事件的触发

    在插入、更新或删除实体时,它们被ABP自动触发。如果你有一个Person实体,你可以注册EntityCreatedEventData,当一个新的Person创建并插入到数据库后,就可以收到通知。这些事件也支持继承,如果你有一个继承自Person的Student类,并且注册了EntityCreatedEventData,当一个Person或Student被插入后,你也会收到通知。

    参阅 ABP框架 - 实体 ,使用AggregateRoot类的DomainEvents集合。

    1. AbpDbContext in Abp.EntityFramework

       public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken)
       {
           try
           {
               var changeReport = ApplyAbpConcepts();
               var result = await base.SaveChangesAsync(cancellationToken);
               await EntityChangeEventHelper.TriggerEventsAsync(changeReport);
               return result;
           }
           catch (DbEntityValidationException ex)
           {
               LogDbEntityValidationException(ex);
               throw;
           }
       }
      
       protected virtual EntityChangeReport ApplyAbpConcepts()
       {
           var changeReport = new EntityChangeReport();
      
           var userId = GetAuditUserId();
      
           var entries = ChangeTracker.Entries().ToList();
           foreach (var entry in entries)
           {
               switch (entry.State)
               {
                   case EntityState.Added:
                       CheckAndSetId(entry.Entity);
                       CheckAndSetMustHaveTenantIdProperty(entry.Entity);
                       CheckAndSetMayHaveTenantIdProperty(entry.Entity);
                       SetCreationAuditProperties(entry.Entity, userId);
                       changeReport.ChangedEntities.Add(new EntityChangeEntry(entry.Entity, EntityChangeType.Created));
                       break;
                   case EntityState.Modified:
                       SetModificationAuditProperties(entry, userId);
                       if (entry.Entity is ISoftDelete && entry.Entity.As<ISoftDelete>().IsDeleted)
                       {
                           SetDeletionAuditProperties(entry.Entity, userId);
                           changeReport.ChangedEntities.Add(new EntityChangeEntry(entry.Entity, EntityChangeType.Deleted));
                       }
                       else
                       {
                           changeReport.ChangedEntities.Add(new EntityChangeEntry(entry.Entity, EntityChangeType.Updated));
                       }
      
                       break;
                   case EntityState.Deleted:
                       CancelDeletionForSoftDelete(entry);
                       SetDeletionAuditProperties(entry.Entity, userId);
                       changeReport.ChangedEntities.Add(new EntityChangeEntry(entry.Entity, EntityChangeType.Deleted));
                       break;
               }
      
               AddDomainEvents(changeReport.DomainEvents, entry.Entity);
           }
      
           return changeReport;
       }
      
       protected virtual void AddDomainEvents(List<DomainEventEntry> domainEvents, object entityAsObj)
       {
           var generatesDomainEventsEntity = entityAsObj as IGeneratesDomainEvents;
           if (generatesDomainEventsEntity == null)
           {
               return;
           }
      
           if (generatesDomainEventsEntity.DomainEvents.IsNullOrEmpty())
           {
               return;
           }
      
           domainEvents.AddRange(generatesDomainEventsEntity.DomainEvents.Select(eventData => new DomainEventEntry(entityAsObj, eventData)));
           generatesDomainEventsEntity.DomainEvents.Clear();
       }
      
    2. EntityChangeEventHelper in Abp.Events.Bus.Entities

       public class EntityChangeEventHelper : ITransientDependency, IEntityChangeEventHelper
       {
       	public IEventBus EventBus { get; set; }
       
       	private readonly IUnitOfWorkManager _unitOfWorkManager;
       
       	public EntityChangeEventHelper(IUnitOfWorkManager unitOfWorkManager)
       	{
       		_unitOfWorkManager = unitOfWorkManager;
       		EventBus = NullEventBus.Instance;
       	}
       
       	public virtual void TriggerEvents(EntityChangeReport changeReport)
       	{
       		TriggerEventsInternal(changeReport);
       
       		if (changeReport.IsEmpty() || _unitOfWorkManager.Current == null)
       		{
       			return;
       		}
       
       		_unitOfWorkManager.Current.SaveChanges();
       	}
       
       	public Task TriggerEventsAsync(EntityChangeReport changeReport)
       	{
       		TriggerEventsInternal(changeReport);
       
       		if (changeReport.IsEmpty() || _unitOfWorkManager.Current == null)
       		{
       			return Task.FromResult(0);
       		}
       
       		return _unitOfWorkManager.Current.SaveChangesAsync();
       	}
       
       	public virtual void TriggerEntityCreatingEvent(object entity)
       	{
       		TriggerEventWithEntity(typeof(EntityCreatingEventData<>), entity, true);
       	}
       
       	public virtual void TriggerEntityCreatedEventOnUowCompleted(object entity)
       	{
       		TriggerEventWithEntity(typeof(EntityCreatedEventData<>), entity, false);
       	}
       
       	public virtual void TriggerEntityUpdatingEvent(object entity)
       	{
       		TriggerEventWithEntity(typeof(EntityUpdatingEventData<>), entity, true);
       	}
       
       	public virtual void TriggerEntityUpdatedEventOnUowCompleted(object entity)
       	{
       		TriggerEventWithEntity(typeof(EntityUpdatedEventData<>), entity, false);
       	}
       
       	public virtual void TriggerEntityDeletingEvent(object entity)
       	{
       		TriggerEventWithEntity(typeof(EntityDeletingEventData<>), entity, true);
       	}
       
       	public virtual void TriggerEntityDeletedEventOnUowCompleted(object entity)
       	{
       		TriggerEventWithEntity(typeof(EntityDeletedEventData<>), entity, false);
       	}
       
       	public virtual void TriggerEventsInternal(EntityChangeReport changeReport)
       	{
       		TriggerEntityChangeEvents(changeReport.ChangedEntities);
       		TriggerDomainEvents(changeReport.DomainEvents);
       	}
       
       	protected virtual void TriggerEntityChangeEvents(List<EntityChangeEntry> changedEntities)
       	{
       		foreach (var changedEntity in changedEntities)
       		{
       			switch (changedEntity.ChangeType)
       			{
       				case EntityChangeType.Created:
       					TriggerEntityCreatingEvent(changedEntity.Entity);
       					TriggerEntityCreatedEventOnUowCompleted(changedEntity.Entity);
       					break;
       				case EntityChangeType.Updated:
       					TriggerEntityUpdatingEvent(changedEntity.Entity);
       					TriggerEntityUpdatedEventOnUowCompleted(changedEntity.Entity);
       					break;
       				case EntityChangeType.Deleted:
       					TriggerEntityDeletingEvent(changedEntity.Entity);
       					TriggerEntityDeletedEventOnUowCompleted(changedEntity.Entity);
       					break;
       				default:
       					throw new AbpException("Unknown EntityChangeType: " + changedEntity.ChangeType);
       			}
       		}
       	}
       
       	protected virtual void TriggerDomainEvents(List<DomainEventEntry> domainEvents)
       	{
       		foreach (var domainEvent in domainEvents)
       		{
       			EventBus.Trigger(domainEvent.EventData.GetType(), domainEvent.SourceEntity, domainEvent.EventData);
       		}
       	}
       
       	protected virtual void TriggerEventWithEntity(Type genericEventType, object entity, bool triggerInCurrentUnitOfWork)
       	{
       		var entityType = entity.GetType();
       		var eventType = genericEventType.MakeGenericType(entityType);
       
       		if (triggerInCurrentUnitOfWork || _unitOfWorkManager.Current == null)
       		{
       			EventBus.Trigger(eventType, (IEventData)Activator.CreateInstance(eventType, new[] { entity }));
       			return;
       		}
       
       		_unitOfWorkManager.Current.Completed += (sender, args) => EventBus.Trigger(eventType, (IEventData)Activator.CreateInstance(eventType, new[] { entity }));
       	}
       }
      

    事件的处理

    处理一个事件,只要提供一个实现IEventHandler接口的类就可以了。

    public class ActivityWriter : IEventHandler<TaskCompletedEventData>, ITransientDependency
    {
    	public void HandleEvent(TaskCompletedEventData eventData)
    	{
    		WriteActivity("A task is completed by id = " + eventData.TaskId);
    	}
    }
    

    处理程序的自动注册

    上例因为实现了ITransientDependency,它会被注册到Ioc容器,而ABP也会自动把它们注册到事件总线,当一个事件发生,ABP使用Ioc容器得到处理程序的引用,并在事件处理后释放该引用。在ABP里,这是使用事件总线的推荐的方式。

    internal class EventBusInstaller : IWindsorInstaller
    {
    	//……
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            if (_eventBusConfiguration.UseDefaultEventBus)
            {
                container.Register(
                    Component.For<IEventBus>().UsingFactoryMethod(() => EventBus.Default).LifestyleSingleton()
                    );
            }
            else
            {
                container.Register(
                    Component.For<IEventBus>().ImplementedBy<EventBus>().LifestyleSingleton()
                    );
            }
    
            _eventBus = container.Resolve<IEventBus>();
            container.Kernel.ComponentRegistered += Kernel_ComponentRegistered;
        }
    
        private 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], new IocHandlerFactory(_iocResolver, handler.ComponentModel.Implementation));
                }
            }
        }
    }
    
    
    public class IocHandlerFactory : IEventHandlerFactory
    {
        public Type HandlerType { get; private set; }
        private readonly IIocResolver _iocResolver;
        public IocHandlerFactory(IIocResolver iocResolver, Type handlerType)
        {
            _iocResolver = iocResolver;
            HandlerType = handlerType;
        }
    
        public IEventHandler GetHandler()
        {
            return (IEventHandler)_iocResolver.Resolve(HandlerType);
        }
        public void ReleaseHandler(IEventHandler handler)
        {
            _iocResolver.Release(handler);
        }
    }
    

    手动注册

    public class EventBus : IEventBus
    {
        /// <inheritdoc/>
        public IDisposable Register<TEventData>(Action<TEventData> action) where TEventData : IEventData
        {
            return Register(typeof(TEventData), new ActionEventHandler<TEventData>(action));
        }
        /// <inheritdoc/>
        public IDisposable Register<TEventData>(IEventHandler<TEventData> handler) where TEventData : IEventData
        {
            return Register(typeof(TEventData), handler);
        }
        /// <inheritdoc/>
        public IDisposable Register<TEventData, THandler>()
            where TEventData : IEventData
            where THandler : IEventHandler<TEventData>, new()
        {
            return Register(typeof(TEventData), new TransientEventHandlerFactory<THandler>());
        }
        /// <inheritdoc/>
        public IDisposable Register(Type eventType, IEventHandler handler)
        {
            return Register(eventType, new SingleInstanceHandlerFactory(handler));
        }
        /// <inheritdoc/>
        public IDisposable Register<TEventData>(IEventHandlerFactory handlerFactory) where TEventData : IEventData
        {
            return Register(typeof(TEventData), handlerFactory);
        }
        /// <inheritdoc/>
        public IDisposable Register(Type eventType, IEventHandlerFactory handlerFactory)
        {
            GetOrCreateHandlerFactories(eventType)
                .Locking(factories => factories.Add(handlerFactory));
    
            return new FactoryUnregistrar(this, eventType, handlerFactory);
        }
    

    事件总线的Register方法有几个重载,也就提供了多种注册方式。

    接受一个委托

    EventBus.Register<TaskCompletedEventData>(eventData =>
    {
        WriteActivity("A task is completed by id = " + eventData.TaskId);
    });
    

    处理程序

    internal class ActionEventHandler<TEventData> :
        IEventHandler<TEventData>,
        ITransientDependency
    {
        /// <summary>
        /// Action to handle the event.
        /// </summary>
        public Action<TEventData> Action { get; private set; }
    
        /// <summary>
        /// Creates a new instance of <see cref="ActionEventHandler{TEventData}"/>.
        /// </summary>
        /// <param name="handler">Action to handle the event</param>
        public ActionEventHandler(Action<TEventData> handler)
        {
            Action = handler;
        }
    
        /// <summary>
        /// Handles the event.
        /// </summary>
        /// <param name="eventData"></param>
        public void HandleEvent(TEventData eventData)
        {
            Action(eventData);
        }
    }
    

    接受一个实现了IEventHantler的对象

    EventBus.Register<TaskCompletedEventData>(new ActivityWriter());
    

    注册为一个SingleInstanceHandlerFactory

    internal class SingleInstanceHandlerFactory : IEventHandlerFactory
    {
    
        public IEventHandler HandlerInstance { get; private set; }
    
        public SingleInstanceHandlerFactory(IEventHandler handler)
        {
            HandlerInstance = handler;
        }
    
        public IEventHandler GetHandler()
        {
            return HandlerInstance;
        }
    
        public void ReleaseHandler(IEventHandler handler)
        {
            
        }
    }
    

    接受两个泛型参数

    EventBus.Register<TaskCompletedEventData, ActivityWriter>();
    

    注册为一个TransientEventHandlerFactory

    internal class TransientEventHandlerFactory<THandler> : IEventHandlerFactory 
        where THandler : IEventHandler, new()
    {
        public IEventHandler GetHandler()
        {
            return new THandler();
        }
        public void ReleaseHandler(IEventHandler handler)
        {
            if (handler is IDisposable)
            {
                (handler as IDisposable).Dispose();
            }
        }
    }
    

    直接注册一个IEventHandlerFactory

    上面的几种注册方式,最终都是在间接调用下面这个方法

        public IDisposable Register(Type eventType, IEventHandlerFactory handlerFactory)
        {
            GetOrCreateHandlerFactories(eventType)
                .Locking(factories => factories.Add(handlerFactory));
    
            return new FactoryUnregistrar(this, eventType, handlerFactory);
        }
    

    事件处理的取消注册

    1. 最简单的方式就是释放Register方法返回的值

       //Register to an event...
       var registration = EventBus.Register<TaskCompletedEventData>(eventData => WriteActivity("A task is completed by id = " + eventData.TaskId) );
       //Unregister from event
       registration.Dispose();
      
    2. Unregister方法

       //Create a handler
       var handler = new ActivityWriter();
      
       //Register to the event
       EventBus.Register<TaskCompletedEventData>(handler);
      
       //Unregister from event
       EventBus.Unregister<TaskCompletedEventData>(handler);
      
    3. EventBus提供了一个UnregisterAll()方法,它反注册一个事件的所有处理程序

    4. UnregisterAll()方法反注册所有事件的所有处理程序。

  • 相关阅读:
    【学习笔记】《Java编程思想》 第1~7章
    CodeForces
    第十六届浙江大学宁波理工学院程序设计大赛 E 雷顿女士与平衡树(并查集)
    第十六届浙江大学宁波理工学院程序设计大赛 D 雷顿女士与分队hard version(dp)
    CodeForces 862B(思维+二分图染色)
    CodeForces
    CodeForces
    CodeForces
    CodeForces
    CodeForces
  • 原文地址:https://www.cnblogs.com/wj033/p/6492836.html
Copyright © 2011-2022 走看看