using System.Collections.Concurrent;
using GFramework.Core.Abstractions.Architectures;
using GFramework.Core.Abstractions.Ioc;
using GFramework.Core.Abstractions.Logging;
using GFramework.Core.Abstractions.Rule;
using GFramework.Cqrs.Abstractions.Cqrs;
using GFramework.Cqrs.Notification;
using ICqrsRuntime = GFramework.Core.Abstractions.Cqrs.ICqrsRuntime;
namespace GFramework.Cqrs.Internal;
///
/// GFramework 自有 CQRS 运行时分发器。
/// 该类型负责解析请求/通知处理器,并在调用前为上下文感知对象注入当前 CQRS 分发上下文。
///
internal sealed class CqrsDispatcher(
IIocContainer container,
ILogger logger,
INotificationPublisher notificationPublisher) : ICqrsRuntime
{
// 卸载安全的进程级缓存:当 generated registry 提供 request invoker 元数据时,
// registrar 会按请求/响应类型对把它们写入这里;若类型被卸载,条目会自然失效。
private static readonly WeakTypePairCache
GeneratedRequestInvokers = new();
// 卸载安全的进程级缓存:当 generated registry 提供 stream invoker 元数据时,
// registrar 会按流式请求/响应类型对把它们写入这里;若类型被卸载,条目会自然失效。
private static readonly WeakTypePairCache
GeneratedStreamInvokers = new();
// 卸载安全的进程级缓存:通知类型只以弱键语义保留。
// 若插件/热重载程序集中的通知类型被卸载,对应分发绑定会自然失效,下次命中时再重新计算。
private static readonly WeakKeyCache
NotificationDispatchBindings = new();
// 卸载安全的进程级缓存:请求/响应类型对采用弱键缓存,避免流式消息类型被静态字典永久保留。
private static readonly WeakTypePairCache
StreamDispatchBindings = new();
// 卸载安全的进程级缓存:请求/响应类型对命中后复用强类型 dispatch binding;
// 若任一类型被回收,后续首次发送时会按当前加载状态重新生成。
private static readonly WeakTypePairCache
RequestDispatchBindings = new();
// 静态方法定义缓存:这些反射查找与消息类型无关,只需解析一次即可复用。
private static readonly MethodInfo RequestHandlerInvokerMethodDefinition = typeof(CqrsDispatcher)
.GetMethod(nameof(InvokeRequestHandlerAsync), BindingFlags.NonPublic | BindingFlags.Static)!;
private static readonly MethodInfo RequestPipelineInvokerMethodDefinition = typeof(CqrsDispatcher)
.GetMethod(nameof(InvokeRequestPipelineExecutorAsync), BindingFlags.NonPublic | BindingFlags.Static)!;
private static readonly MethodInfo NotificationHandlerInvokerMethodDefinition = typeof(CqrsDispatcher)
.GetMethod(nameof(InvokeNotificationHandlerAsync), BindingFlags.NonPublic | BindingFlags.Static)!;
private static readonly MethodInfo StreamHandlerInvokerMethodDefinition = typeof(CqrsDispatcher)
.GetMethod(nameof(InvokeStreamHandler), BindingFlags.NonPublic | BindingFlags.Static)!;
private readonly INotificationPublisher _notificationPublisher = notificationPublisher
?? throw new ArgumentNullException(
nameof(notificationPublisher));
///
/// 发布通知到所有已注册处理器。
///
/// 通知类型。
/// 当前 CQRS 分发上下文,用于上下文感知处理器注入。
/// 通知对象。
/// 取消令牌。
public async ValueTask PublishAsync(
ICqrsContext context,
TNotification notification,
CancellationToken cancellationToken = default)
where TNotification : INotification
{
ArgumentNullException.ThrowIfNull(context);
ArgumentNullException.ThrowIfNull(notification);
var notificationType = notification.GetType();
var dispatchBinding = NotificationDispatchBindings.GetOrAdd(
notificationType,
static notificationType => CreateNotificationDispatchBinding(notificationType));
var handlers = container.GetAll(dispatchBinding.HandlerType);
if (handlers.Count == 0)
{
logger.Debug($"No CQRS notification handler registered for {notificationType.FullName}.");
return;
}
var publishContext = CreateNotificationPublishContext(notification, handlers, context, dispatchBinding.Invoker);
await _notificationPublisher.PublishAsync(publishContext, cancellationToken).ConfigureAwait(false);
}
///
/// 发送请求并返回结果。
///
/// 响应类型。
/// 当前 CQRS 分发上下文,用于上下文感知处理器注入。
/// 请求对象。
/// 取消令牌。
/// 请求响应。
public async ValueTask SendAsync(
ICqrsContext context,
IRequest request,
CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(context);
ArgumentNullException.ThrowIfNull(request);
var requestType = request.GetType();
var dispatchBinding = GetRequestDispatchBinding(requestType);
var handler = container.Get(dispatchBinding.HandlerType)
?? throw new InvalidOperationException(
$"No CQRS request handler registered for {requestType.FullName}.");
PrepareHandler(handler, context);
var behaviors = container.GetAll(dispatchBinding.BehaviorType);
foreach (var behavior in behaviors)
PrepareHandler(behavior, context);
if (behaviors.Count == 0)
return await dispatchBinding.RequestInvoker(handler, request, cancellationToken).ConfigureAwait(false);
return await dispatchBinding.GetPipelineExecutor(behaviors.Count)
.Invoke(handler, behaviors, request, cancellationToken)
.ConfigureAwait(false);
}
///
/// 创建流式请求并返回异步响应序列。
///
/// 响应元素类型。
/// 当前 CQRS 分发上下文,用于上下文感知处理器注入。
/// 流式请求对象。
/// 取消令牌。
/// 异步响应序列。
public IAsyncEnumerable CreateStream(
ICqrsContext context,
IStreamRequest request,
CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(context);
ArgumentNullException.ThrowIfNull(request);
var requestType = request.GetType();
var dispatchBinding = StreamDispatchBindings.GetOrAdd(
requestType,
typeof(TResponse),
static (requestType, responseType) => CreateStreamDispatchBinding(requestType, responseType));
var handler = container.Get(dispatchBinding.HandlerType)
?? throw new InvalidOperationException(
$"No CQRS stream handler registered for {requestType.FullName}.");
PrepareHandler(handler, context);
return (IAsyncEnumerable)dispatchBinding.Invoker(handler, request, cancellationToken);
}
///
/// 为上下文感知处理器注入当前 CQRS 分发上下文。
///
/// 处理器实例。
/// 当前 CQRS 分发上下文。
private static void PrepareHandler(object handler, ICqrsContext context)
{
if (handler is IContextAware contextAware)
{
if (context is not IArchitectureContext architectureContext)
throw new InvalidOperationException(
"The current CQRS context does not implement IArchitectureContext, so it cannot be injected into IContextAware handlers.");
contextAware.SetContext(architectureContext);
}
}
///
/// 为指定请求类型构造完整分发绑定,把服务类型与强类型调用委托一次性收敛到同一缓存项。
///
private static RequestDispatchBinding CreateRequestDispatchBinding(Type requestType)
{
var generatedDescriptor = TryGetGeneratedRequestInvokerDescriptor(requestType);
if (generatedDescriptor is not null)
{
var resolvedGeneratedDescriptor = generatedDescriptor.Value;
return new RequestDispatchBinding(
resolvedGeneratedDescriptor.HandlerType,
typeof(IPipelineBehavior<,>).MakeGenericType(requestType, typeof(TResponse)),
resolvedGeneratedDescriptor.Invoker,
requestType);
}
return new RequestDispatchBinding(
typeof(IRequestHandler<,>).MakeGenericType(requestType, typeof(TResponse)),
typeof(IPipelineBehavior<,>).MakeGenericType(requestType, typeof(TResponse)),
CreateRequestInvoker(requestType),
requestType);
}
///
/// 获取指定请求/响应类型对的 dispatch binding;若缓存未命中则按当前加载状态创建。
///
private static RequestDispatchBinding GetRequestDispatchBinding(Type requestType)
{
var bindingBox = RequestDispatchBindings.GetOrAdd(
requestType,
typeof(TResponse),
static (cachedRequestType, cachedResponseType) =>
CreateRequestDispatchBindingBox(cachedRequestType, cachedResponseType));
return bindingBox.Get();
}
///
/// 为弱键请求缓存创建强类型 binding 盒子,避免 value-type 响应走 object 结果桥接。
///
private static RequestDispatchBindingBox CreateRequestDispatchBindingBox(
Type requestType,
Type responseType)
{
if (responseType != typeof(TResponse))
throw new InvalidOperationException(
$"Request dispatch binding cache expected response type {typeof(TResponse).FullName}, but received {responseType.FullName}.");
return RequestDispatchBindingBox.Create(CreateRequestDispatchBinding(requestType));
}
///
/// 尝试从容器已注册的 generated request invoker provider 中获取指定请求/响应类型对的元数据。
///
/// 当前请求响应类型。
/// 请求运行时类型。
/// 命中时返回强类型化后的描述符;否则返回 。
private static RequestInvokerDescriptor? TryGetGeneratedRequestInvokerDescriptor(Type requestType)
{
return GeneratedRequestInvokers.TryGetValue(requestType, typeof(TResponse), out var metadata) &&
metadata is not null
? CreateRequestInvokerDescriptor(requestType, metadata)
: null;
}
///
/// 把 provider 返回的弱类型描述符转换为 dispatcher 内部使用的强类型 request invoker 描述符。
///
/// 当前请求响应类型。
/// 请求运行时类型。
/// provider 返回的弱类型描述符。
/// 可直接用于创建 request dispatch binding 的强类型描述符。
/// 当 provider 返回的委托签名与当前请求/响应类型对不匹配时抛出。
private static RequestInvokerDescriptor CreateRequestInvokerDescriptor(
Type requestType,
GeneratedRequestInvokerMetadata descriptor)
{
if (!descriptor.InvokerMethod.IsStatic)
{
throw new InvalidOperationException(
$"Generated CQRS request invoker provider returned a non-static invoker method for request type {requestType.FullName} and response type {typeof(TResponse).FullName}.");
}
try
{
if (Delegate.CreateDelegate(typeof(RequestInvoker), descriptor.InvokerMethod) is not
RequestInvoker invoker)
{
throw new InvalidOperationException(
$"Generated CQRS request invoker provider returned an incompatible invoker for request type {requestType.FullName} and response type {typeof(TResponse).FullName}.");
}
return new RequestInvokerDescriptor(descriptor.HandlerType, invoker);
}
catch (ArgumentException exception)
{
throw new InvalidOperationException(
$"Generated CQRS request invoker provider returned an incompatible invoker for request type {requestType.FullName} and response type {typeof(TResponse).FullName}.",
exception);
}
}
///
/// 为指定通知类型构造完整分发绑定,把服务类型与调用委托聚合到同一缓存项。
///
private static NotificationDispatchBinding CreateNotificationDispatchBinding(Type notificationType)
{
return new NotificationDispatchBinding(
typeof(INotificationHandler<>).MakeGenericType(notificationType),
CreateNotificationInvoker(notificationType));
}
///
/// 为指定流式请求类型构造完整分发绑定,把服务类型与调用委托聚合到同一缓存项。
///
private static StreamDispatchBinding CreateStreamDispatchBinding(Type requestType, Type responseType)
{
var generatedDescriptor = TryGetGeneratedStreamInvokerDescriptor(requestType, responseType);
if (generatedDescriptor is not null)
{
var resolvedGeneratedDescriptor = generatedDescriptor.Value;
return new StreamDispatchBinding(
resolvedGeneratedDescriptor.HandlerType,
resolvedGeneratedDescriptor.Invoker);
}
return new StreamDispatchBinding(
typeof(IStreamRequestHandler<,>).MakeGenericType(requestType, responseType),
CreateStreamInvoker(requestType, responseType));
}
///
/// 尝试从容器已注册的 generated stream invoker provider 中获取指定流式请求/响应类型对的元数据。
///
/// 流式请求运行时类型。
/// 流式响应元素类型。
/// 命中时返回强类型化后的描述符;否则返回 。
private static StreamInvokerDescriptor? TryGetGeneratedStreamInvokerDescriptor(Type requestType, Type responseType)
{
return GeneratedStreamInvokers.TryGetValue(requestType, responseType, out var metadata) &&
metadata is not null
? CreateStreamInvokerDescriptor(requestType, responseType, metadata)
: null;
}
///
/// 把 provider 返回的弱类型描述符转换为 dispatcher 内部使用的 stream invoker 描述符。
///
/// 流式请求运行时类型。
/// 流式响应元素类型。
/// provider 返回的弱类型描述符。
/// 可直接用于创建 stream dispatch binding 的描述符。
/// 当 provider 返回的委托签名与当前流式请求/响应类型对不匹配时抛出。
private static StreamInvokerDescriptor CreateStreamInvokerDescriptor(
Type requestType,
Type responseType,
GeneratedStreamInvokerMetadata descriptor)
{
if (!descriptor.InvokerMethod.IsStatic)
{
throw new InvalidOperationException(
$"Generated CQRS stream invoker provider returned a non-static invoker method for request type {requestType.FullName} and response type {responseType.FullName}.");
}
try
{
if (Delegate.CreateDelegate(typeof(StreamInvoker), descriptor.InvokerMethod) is not StreamInvoker invoker)
{
throw new InvalidOperationException(
$"Generated CQRS stream invoker provider returned an incompatible invoker for request type {requestType.FullName} and response type {responseType.FullName}.");
}
return new StreamInvokerDescriptor(descriptor.HandlerType, invoker);
}
catch (ArgumentException exception)
{
throw new InvalidOperationException(
$"Generated CQRS stream invoker provider returned an incompatible invoker for request type {requestType.FullName} and response type {responseType.FullName}.",
exception);
}
}
///
/// 生成请求处理器调用委托,避免每次发送都重复反射。
///
private static RequestInvoker CreateRequestInvoker(Type requestType)
{
var method = RequestHandlerInvokerMethodDefinition
.MakeGenericMethod(requestType, typeof(TResponse));
return (RequestInvoker)Delegate.CreateDelegate(typeof(RequestInvoker), method);
}
///
/// 生成通知处理器调用委托,避免每次发布都重复反射。
///
private static NotificationInvoker CreateNotificationInvoker(Type notificationType)
{
var method = NotificationHandlerInvokerMethodDefinition
.MakeGenericMethod(notificationType);
return (NotificationInvoker)Delegate.CreateDelegate(typeof(NotificationInvoker), method);
}
///
/// 为当前通知发布调用创建发布上下文,把处理器集合与执行入口收敛到同一对象。
///
/// 通知类型。
/// 当前通知。
/// 当前发布调用已解析到的处理器集合。
/// 当前 CQRS 分发上下文。
/// 执行单个通知处理器时复用的强类型调用委托。
/// 供通知发布器消费的执行上下文。
private static NotificationPublishContext CreateNotificationPublishContext(
TNotification notification,
IReadOnlyList