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; |
||||
using System.Collections.Concurrent; |
using System.Collections.Concurrent; |
||||
using System.Linq; |
|
||||
using System.Reflection; |
|
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
using Volo.Abp.DependencyInjection; |
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.EventBus.Distributed; |
||||
|
|
||||
namespace Volo.Abp.EventBus; |
namespace Volo.Abp.EventBus; |
||||
|
|
||||
public class EventHandlerInvoker : IEventHandlerInvoker, ISingletonDependency |
public class EventHandlerInvoker : IEventHandlerInvoker, ISingletonDependency |
||||
{ |
{ |
||||
private const string EventHandlerMethodName = "HandleEventAsync"; |
private readonly ConcurrentDictionary<string, IEventHandlerMethodExecutor> _cache; |
||||
private readonly ConcurrentDictionary<string, EventHandlerMethodExecutor> _executorCache; |
|
||||
|
|
||||
public EventHandlerInvoker() |
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(); |
if (typeof(ILocalEventHandler<>).MakeGenericType(eventType).IsInstanceOfType(eventHandler)) |
||||
var key = $"{handleType.FullName}_{eventType.FullName}"; |
{ |
||||
|
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 }); |
if (!typeof(ILocalEventHandler<>).MakeGenericType(eventType).IsInstanceOfType(eventHandler) && |
||||
} |
!typeof(IDistributedEventHandler<>).MakeGenericType(eventType).IsInstanceOfType(eventHandler)) |
||||
|
{ |
||||
private static MethodInfo GetHandleEventMethodInfo(Type handleType, Type eventType) |
throw new AbpException("The object instance is not an event handler. Object type: " + eventHandler.GetType().AssemblyQualifiedName); |
||||
{ |
} |
||||
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)); |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,66 +1,34 @@ |
|||||
using System; |
using System; |
||||
using System.Collections.Generic; |
|
||||
using System.Linq.Expressions; |
|
||||
using System.Reflection; |
|
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
using Volo.Abp.EventBus.Distributed; |
||||
|
|
||||
namespace Volo.Abp.EventBus; |
namespace Volo.Abp.EventBus; |
||||
|
|
||||
public class EventHandlerMethodExecutor |
public delegate Task EventHandlerMethodExecutorAsync(IEventHandler target, object parameter); |
||||
{ |
|
||||
private readonly MethodExecutorAsync _executorAsync; |
|
||||
private delegate Task MethodExecutorAsync(IEventHandler target, object[] parameters); |
|
||||
|
|
||||
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) |
return ExecutorAsync(target, parameters); |
||||
{ |
|
||||
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(); |
|
||||
|
|
||||
} |
} |
||||
|
} |
||||
|
|
||||
public static EventHandlerMethodExecutor Create(MethodInfo methodInfo, TypeInfo targetTypeInfo) |
public class DistributedEventHandlerMethodExecutor<TEvent> : IEventHandlerMethodExecutor |
||||
{ |
where TEvent : class |
||||
return new EventHandlerMethodExecutor(methodInfo, targetTypeInfo); |
{ |
||||
} |
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