mirror of https://github.com/abpframework/abp.git
4 changed files with 43 additions and 76 deletions
@ -1,35 +1,40 @@ |
|||
using System; |
|||
using System.Collections.Concurrent; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.EventBus.Distributed; |
|||
|
|||
namespace Volo.Abp.EventBus; |
|||
|
|||
public class EventHandlerInvoker : IEventHandlerInvoker, ISingletonDependency |
|||
{ |
|||
private const string EventHandlerMethodName = "HandleEventAsync"; |
|||
private readonly ConcurrentDictionary<string, EventHandlerMethodExecutor> _executorCache; |
|||
private readonly ConcurrentDictionary<string, IEventHandlerMethodExecutor> _cache; |
|||
|
|||
public EventHandlerInvoker() |
|||
{ |
|||
_executorCache = new ConcurrentDictionary<string, EventHandlerMethodExecutor>(); |
|||
_cache = new ConcurrentDictionary<string, IEventHandlerMethodExecutor>(); |
|||
} |
|||
|
|||
public Task InvokeAsync(IEventHandler eventHandler, object eventData, Type eventType) |
|||
public async Task InvokeAsync(IEventHandler eventHandler, object eventData, Type eventType) |
|||
{ |
|||
var handleType = eventHandler.GetType(); |
|||
var key = $"{handleType.FullName}_{eventType.FullName}"; |
|||
if (typeof(ILocalEventHandler<>).MakeGenericType(eventType).IsInstanceOfType(eventHandler)) |
|||
{ |
|||
var eventHandlerCall = _cache.GetOrAdd($"{typeof(LocalEventHandlerMethodExecutor<>).FullName}{eventHandler.GetType().FullName}-{eventType.FullName}", |
|||
(_) => (IEventHandlerMethodExecutor)Activator.CreateInstance(typeof(LocalEventHandlerMethodExecutor<>).MakeGenericType(eventType))); |
|||
await eventHandlerCall.ExecutorAsync(eventHandler, eventData); |
|||
} |
|||
|
|||
var executor = _executorCache.GetOrAdd(key, _ => EventHandlerMethodExecutor.Create(GetHandleEventMethodInfo(handleType, eventType), handleType.GetTypeInfo())); |
|||
if (typeof(IDistributedEventHandler<>).MakeGenericType(eventType).IsInstanceOfType(eventHandler)) |
|||
{ |
|||
var eventHandlerCall = _cache.GetOrAdd($"{typeof(DistributedEventHandlerMethodExecutor<>).FullName}{eventHandler.GetType().FullName}-{eventType.FullName}", |
|||
(_) => (IEventHandlerMethodExecutor)Activator.CreateInstance(typeof(DistributedEventHandlerMethodExecutor<>).MakeGenericType(eventType))); |
|||
await eventHandlerCall.ExecutorAsync(eventHandler, eventData); |
|||
} |
|||
|
|||
return executor.ExecuteAsync(eventHandler, new[] { eventData }); |
|||
} |
|||
|
|||
private static MethodInfo GetHandleEventMethodInfo(Type handleType, Type eventType) |
|||
{ |
|||
var methods = handleType.GetMethods().Where(x => x.Name == EventHandlerMethodName).ToArray(); |
|||
return methods.Length == 1 ? methods.First() : methods.FirstOrDefault(x => x.GetParameters().Any(param => param.ParameterType == eventType)); |
|||
if (!typeof(ILocalEventHandler<>).MakeGenericType(eventType).IsInstanceOfType(eventHandler) && |
|||
!typeof(IDistributedEventHandler<>).MakeGenericType(eventType).IsInstanceOfType(eventHandler)) |
|||
{ |
|||
throw new AbpException("The object instance is not an event handler. Object type: " + eventHandler.GetType().AssemblyQualifiedName); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,66 +1,34 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq.Expressions; |
|||
using System.Reflection; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.EventBus.Distributed; |
|||
|
|||
namespace Volo.Abp.EventBus; |
|||
|
|||
public class EventHandlerMethodExecutor |
|||
{ |
|||
private readonly MethodExecutorAsync _executorAsync; |
|||
private delegate Task MethodExecutorAsync(IEventHandler target, object[] parameters); |
|||
public delegate Task EventHandlerMethodExecutorAsync(IEventHandler target, object parameter); |
|||
|
|||
public MethodInfo MethodInfo { get; } |
|||
public interface IEventHandlerMethodExecutor |
|||
{ |
|||
EventHandlerMethodExecutorAsync ExecutorAsync { get; } |
|||
} |
|||
|
|||
public TypeInfo TargetTypeInfo { get; } |
|||
public class LocalEventHandlerMethodExecutor<TEvent> : IEventHandlerMethodExecutor |
|||
where TEvent : class |
|||
{ |
|||
public EventHandlerMethodExecutorAsync ExecutorAsync => (target, parameter) => target.As<ILocalEventHandler<TEvent>>().HandleEventAsync(parameter.As<TEvent>()); |
|||
|
|||
private EventHandlerMethodExecutor(MethodInfo methodInfo, TypeInfo targetTypeInfo) |
|||
public Task ExecuteAsync(IEventHandler target, TEvent parameters) |
|||
{ |
|||
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<Expression>(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<MethodExecutorAsync>(castMethodCall, targetParameter, parametersParameter); |
|||
return lambda.Compile(); |
|||
|
|||
return ExecutorAsync(target, parameters); |
|||
} |
|||
} |
|||
|
|||
public static EventHandlerMethodExecutor Create(MethodInfo methodInfo, TypeInfo targetTypeInfo) |
|||
{ |
|||
return new EventHandlerMethodExecutor(methodInfo, targetTypeInfo); |
|||
} |
|||
public class DistributedEventHandlerMethodExecutor<TEvent> : IEventHandlerMethodExecutor |
|||
where TEvent : class |
|||
{ |
|||
public EventHandlerMethodExecutorAsync ExecutorAsync => (target, parameter) => target.As<IDistributedEventHandler<TEvent>>().HandleEventAsync(parameter.As<TEvent>()); |
|||
|
|||
public Task ExecuteAsync(IEventHandler target, object[] parameters) |
|||
public Task ExecuteAsync(IEventHandler target, TEvent parameters) |
|||
{ |
|||
return _executorAsync(target, parameters); |
|||
return ExecutorAsync(target, parameters); |
|||
} |
|||
} |
|||
|
|||
Loading…
Reference in new issue