diff --git a/framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AzureDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AzureDistributedEventBus.cs index 49add5df84..18fb5c6e9e 100644 --- a/framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AzureDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus.Azure/Volo/Abp/EventBus/Azure/AzureDistributedEventBus.cs @@ -39,13 +39,15 @@ public class AzureDistributedEventBus : DistributedEventBusBase, ISingletonDepen IOptions abpAzureEventBusOptions, IAzureServiceBusSerializer serializer, IAzureServiceBusMessageConsumerFactory messageConsumerFactory, - IPublisherPool publisherPool) + IPublisherPool publisherPool, + IEventHandlerInvoker eventHandlerInvoker) : base(serviceScopeFactory, currentTenant, unitOfWorkManager, abpDistributedEventBusOptions, guidGenerator, - clock) + clock, + eventHandlerInvoker) { _options = abpAzureEventBusOptions.Value; _serializer = serializer; diff --git a/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs index ec1901161a..a19b01311c 100644 --- a/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs @@ -39,14 +39,16 @@ public class KafkaDistributedEventBus : DistributedEventBusBase, ISingletonDepen IKafkaSerializer serializer, IProducerPool producerPool, IGuidGenerator guidGenerator, - IClock clock) + IClock clock, + IEventHandlerInvoker eventHandlerInvoker) : base( serviceScopeFactory, currentTenant, unitOfWorkManager, abpDistributedEventBusOptions, guidGenerator, - clock) + clock, + eventHandlerInvoker) { AbpKafkaEventBusOptions = abpKafkaEventBusOptions.Value; MessageConsumerFactory = messageConsumerFactory; diff --git a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs index 1564cfd213..38f8e4eea5 100644 --- a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs @@ -44,14 +44,16 @@ public class RabbitMqDistributedEventBus : DistributedEventBusBase, ISingletonDe ICurrentTenant currentTenant, IUnitOfWorkManager unitOfWorkManager, IGuidGenerator guidGenerator, - IClock clock) + IClock clock, + IEventHandlerInvoker eventHandlerInvoker) : base( serviceScopeFactory, currentTenant, unitOfWorkManager, distributedEventBusOptions, guidGenerator, - clock) + clock, + eventHandlerInvoker) { ConnectionPool = connectionPool; Serializer = serializer; diff --git a/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs index 0542a705eb..d637f3fe89 100644 --- a/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs @@ -38,14 +38,16 @@ public class RebusDistributedEventBus : DistributedEventBusBase, ISingletonDepen IOptions abpEventBusRebusOptions, IRebusSerializer serializer, IGuidGenerator guidGenerator, - IClock clock) : + IClock clock, + IEventHandlerInvoker eventHandlerInvoker) : base( serviceScopeFactory, currentTenant, unitOfWorkManager, abpDistributedEventBusOptions, guidGenerator, - clock) + clock, + eventHandlerInvoker) { Rebus = rebus; Serializer = serializer; diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/DistributedEventBusBase.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/DistributedEventBusBase.cs index dee9d1f7d3..6547c1686c 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/DistributedEventBusBase.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/DistributedEventBusBase.cs @@ -22,11 +22,13 @@ public abstract class DistributedEventBusBase : EventBusBase, IDistributedEventB IUnitOfWorkManager unitOfWorkManager, IOptions abpDistributedEventBusOptions, IGuidGenerator guidGenerator, - IClock clock + IClock clock, + IEventHandlerInvoker eventHandlerInvoker ) : base( serviceScopeFactory, currentTenant, - unitOfWorkManager) + unitOfWorkManager, + eventHandlerInvoker) { GuidGenerator = guidGenerator; Clock = clock; diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs index 15b597da30..b6805de1ae 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs @@ -22,14 +22,18 @@ public abstract class EventBusBase : IEventBus protected IUnitOfWorkManager UnitOfWorkManager { get; } + protected IEventHandlerInvoker EventHandlerInvoker { get; } + protected EventBusBase( IServiceScopeFactory serviceScopeFactory, ICurrentTenant currentTenant, - IUnitOfWorkManager unitOfWorkManager) + IUnitOfWorkManager unitOfWorkManager, + IEventHandlerInvoker eventHandlerInvoker) { ServiceScopeFactory = serviceScopeFactory; CurrentTenant = currentTenant; UnitOfWorkManager = unitOfWorkManager; + EventHandlerInvoker = eventHandlerInvoker; } /// @@ -210,27 +214,9 @@ public abstract class EventBusBase : IEventBus using (CurrentTenant.Change(GetEventDataTenantId(eventData))) { - if (ReflectionHelper.IsAssignableToGenericType(handlerType, typeof(ILocalEventHandler<>))) - { - var method = typeof(ILocalEventHandler<>) - .MakeGenericType(eventType) - .GetMethod( - nameof(ILocalEventHandler.HandleEventAsync), - new[] { eventType } - ); - - await ((Task)method.Invoke(eventHandlerWrapper.EventHandler, new[] { eventData })); - } - else if (ReflectionHelper.IsAssignableToGenericType(handlerType, typeof(IDistributedEventHandler<>))) + if (ReflectionHelper.IsAssignableToGenericType(handlerType, typeof(ILocalEventHandler<>)) || ReflectionHelper.IsAssignableToGenericType(handlerType, typeof(IDistributedEventHandler<>))) { - var method = typeof(IDistributedEventHandler<>) - .MakeGenericType(eventType) - .GetMethod( - nameof(IDistributedEventHandler.HandleEventAsync), - new[] { eventType } - ); - - await ((Task)method.Invoke(eventHandlerWrapper.EventHandler, new[] { eventData })); + await EventHandlerInvoker.InvokeAsync(eventHandlerWrapper.EventHandler, eventData); } else { diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerInvoker.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerInvoker.cs new file mode 100644 index 0000000000..986615e134 --- /dev/null +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerInvoker.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Concurrent; +using System.Reflection; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.EventBus; + +public class EventHandlerInvoker : IEventHandlerInvoker, ISingletonDependency +{ + private const string EventHandlerMethodName = "HandleEventAsync"; + private readonly ConcurrentDictionary _executorCache; + + public EventHandlerInvoker() + { + _executorCache = new ConcurrentDictionary(); + } + + public Task InvokeAsync(IEventHandler eventHandler, object eventData) + { + var handleType = eventHandler.GetType(); + var executor = _executorCache.GetOrAdd(handleType, type => EventHandlerMethodExecutor.Create(type.GetMethod(EventHandlerMethodName), type.GetTypeInfo())); + + return executor.ExecuteAsync(eventHandler, new[] { eventData }); + } +} diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerMethodExecutor.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerMethodExecutor.cs new file mode 100644 index 0000000000..332b9af1ef --- /dev/null +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventHandlerMethodExecutor.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Reflection; +using System.Threading.Tasks; + +namespace Volo.Abp.EventBus; + +public class EventHandlerMethodExecutor +{ + private readonly MethodExecutorAsync _executorAsync; + private delegate Task MethodExecutorAsync(IEventHandler target, object[] parameters); + + public MethodInfo MethodInfo { get; } + + public TypeInfo TargetTypeInfo { get; } + + private EventHandlerMethodExecutor(MethodInfo methodInfo, TypeInfo targetTypeInfo) + { + if (methodInfo == null) + { + throw new ArgumentNullException(nameof(methodInfo)); + } + + MethodInfo = methodInfo; + TargetTypeInfo = targetTypeInfo; + + _executorAsync = GetExecutorAsync(methodInfo, targetTypeInfo); + } + + private static MethodExecutorAsync GetExecutorAsync(MethodInfo methodInfo, TypeInfo targetTypeInfo) + { + var targetParameter = Expression.Parameter(typeof(IEventHandler), "target"); + var parametersParameter = Expression.Parameter(typeof(object[]), "parameters"); + + var paramInfos = methodInfo.GetParameters(); + var parameters = new List(paramInfos.Length); + + for (var i = 0; i < paramInfos.Length; i++) + { + var paramInfo = paramInfos[i]; + var valueObj = Expression.ArrayIndex(parametersParameter, Expression.Constant(i)); + var valueCast = Expression.Convert(valueObj, paramInfo.ParameterType); + + parameters.Add(valueCast); + } + + var instanceCast = Expression.Convert(targetParameter, targetTypeInfo.AsType()); + var methodCall = Expression.Call(instanceCast, methodInfo, parameters); + + var castMethodCall = Expression.Convert(methodCall, typeof(Task)); + var lambda = Expression.Lambda(castMethodCall, targetParameter, parametersParameter); + return lambda.Compile(); + + } + + public static EventHandlerMethodExecutor Create(MethodInfo methodInfo, TypeInfo targetTypeInfo) + { + return new EventHandlerMethodExecutor(methodInfo, targetTypeInfo); + } + + public Task ExecuteAsync(IEventHandler target, object[] parameters) + { + return _executorAsync(target, parameters); + } +} diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventHandlerInvoker.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventHandlerInvoker.cs new file mode 100644 index 0000000000..37019cce62 --- /dev/null +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventHandlerInvoker.cs @@ -0,0 +1,8 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.EventBus; + +public interface IEventHandlerInvoker +{ + Task InvokeAsync(IEventHandler eventHandler, object eventData); +} diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs index 800c4a61df..3f7dbbc851 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs @@ -33,8 +33,9 @@ public class LocalEventBus : EventBusBase, ILocalEventBus, ISingletonDependency IOptions options, IServiceScopeFactory serviceScopeFactory, ICurrentTenant currentTenant, - IUnitOfWorkManager unitOfWorkManager) - : base(serviceScopeFactory, currentTenant, unitOfWorkManager) + IUnitOfWorkManager unitOfWorkManager, + IEventHandlerInvoker eventHandlerInvoker) + : base(serviceScopeFactory, currentTenant, unitOfWorkManager, eventHandlerInvoker) { Options = options.Value; Logger = NullLogger.Instance;