diff --git a/GFramework.Cqrs.Benchmarks/Messaging/GeneratedRequestLifetimeBenchmarkRegistry.cs b/GFramework.Cqrs.Benchmarks/Messaging/GeneratedRequestLifetimeBenchmarkRegistry.cs
new file mode 100644
index 00000000..85192cc7
--- /dev/null
+++ b/GFramework.Cqrs.Benchmarks/Messaging/GeneratedRequestLifetimeBenchmarkRegistry.cs
@@ -0,0 +1,112 @@
+// Copyright (c) 2025-2026 GeWuYou
+// SPDX-License-Identifier: Apache-2.0
+
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Threading;
+using System.Threading.Tasks;
+using GFramework.Core.Abstractions.Logging;
+using GFramework.Cqrs.Abstractions.Cqrs;
+using Microsoft.Extensions.DependencyInjection;
+
+[assembly: GFramework.Cqrs.CqrsHandlerRegistryAttribute(
+ typeof(GFramework.Cqrs.Benchmarks.Messaging.GeneratedRequestLifetimeBenchmarkRegistry))]
+
+namespace GFramework.Cqrs.Benchmarks.Messaging;
+
+///
+/// 为 request 生命周期矩阵 benchmark 提供 hand-written generated registry,
+/// 以便在默认 generated-provider 宿主路径上比较不同 handler 生命周期的 dispatch 成本。
+///
+public sealed class GeneratedRequestLifetimeBenchmarkRegistry :
+ GFramework.Cqrs.ICqrsHandlerRegistry,
+ GFramework.Cqrs.ICqrsRequestInvokerProvider,
+ GFramework.Cqrs.IEnumeratesCqrsRequestInvokerDescriptors
+{
+ private static readonly GFramework.Cqrs.CqrsRequestInvokerDescriptor Descriptor =
+ new(
+ typeof(IRequestHandler<
+ RequestLifetimeBenchmarks.BenchmarkRequest,
+ RequestLifetimeBenchmarks.BenchmarkResponse>),
+ typeof(GeneratedRequestLifetimeBenchmarkRegistry).GetMethod(
+ nameof(InvokeBenchmarkRequestHandler),
+ BindingFlags.Public | BindingFlags.Static)
+ ?? throw new InvalidOperationException("Missing generated request lifetime benchmark method."));
+
+ private static readonly IReadOnlyList Descriptors =
+ [
+ new GFramework.Cqrs.CqrsRequestInvokerDescriptorEntry(
+ typeof(RequestLifetimeBenchmarks.BenchmarkRequest),
+ typeof(RequestLifetimeBenchmarks.BenchmarkResponse),
+ Descriptor)
+ ];
+
+ ///
+ /// 参与程序集注册入口,但不在这里直接写入 handler 生命周期。
+ ///
+ /// 当前 generated registry 拥有的服务集合。
+ /// 用于记录 generated registry 注册行为的日志器。
+ ///
+ /// 生命周期矩阵需要让 benchmark 主体显式控制 `Singleton / Transient` 变量。
+ /// 因此 registry 只负责暴露 generated descriptor,不在这里抢先注册 handler,避免把默认单例注册混入比较结果。
+ ///
+ public void Register(IServiceCollection services, ILogger logger)
+ {
+ ArgumentNullException.ThrowIfNull(services);
+ ArgumentNullException.ThrowIfNull(logger);
+
+ logger.Debug("Registered generated request lifetime benchmark descriptors.");
+ }
+
+ ///
+ /// 返回当前 provider 暴露的全部 generated request invoker 描述符。
+ ///
+ /// 当前 benchmark 需要的 request invoker 描述符集合。
+ public IReadOnlyList GetDescriptors()
+ {
+ return Descriptors;
+ }
+
+ ///
+ /// 为目标请求/响应类型对返回 generated request invoker 描述符。
+ ///
+ /// 待匹配的请求类型。
+ /// 待匹配的响应类型。
+ /// 命中时返回的 generated descriptor。
+ /// 命中当前 benchmark 的请求/响应类型对时返回 。
+ public bool TryGetDescriptor(
+ Type requestType,
+ Type responseType,
+ out GFramework.Cqrs.CqrsRequestInvokerDescriptor? descriptor)
+ {
+ if (requestType == typeof(RequestLifetimeBenchmarks.BenchmarkRequest) &&
+ responseType == typeof(RequestLifetimeBenchmarks.BenchmarkResponse))
+ {
+ descriptor = Descriptor;
+ return true;
+ }
+
+ descriptor = null;
+ return false;
+ }
+
+ ///
+ /// 模拟 generated request invoker provider 为生命周期矩阵 benchmark 产出的开放静态调用入口。
+ ///
+ /// 当前请求对应的 handler 实例。
+ /// 待分发的 request。
+ /// 调用方传入的取消令牌。
+ /// 交给目标 request handler 处理后的响应任务。
+ public static ValueTask InvokeBenchmarkRequestHandler(
+ object handler,
+ object request,
+ CancellationToken cancellationToken)
+ {
+ var typedHandler = (IRequestHandler<
+ RequestLifetimeBenchmarks.BenchmarkRequest,
+ RequestLifetimeBenchmarks.BenchmarkResponse>)handler;
+ var typedRequest = (RequestLifetimeBenchmarks.BenchmarkRequest)request;
+ return typedHandler.Handle(typedRequest, cancellationToken);
+ }
+}
diff --git a/GFramework.Cqrs.Benchmarks/Messaging/RequestLifetimeBenchmarks.cs b/GFramework.Cqrs.Benchmarks/Messaging/RequestLifetimeBenchmarks.cs
index 735705db..2e342dd6 100644
--- a/GFramework.Cqrs.Benchmarks/Messaging/RequestLifetimeBenchmarks.cs
+++ b/GFramework.Cqrs.Benchmarks/Messaging/RequestLifetimeBenchmarks.cs
@@ -85,14 +85,18 @@ public class RequestLifetimeBenchmarks
MinLevel = LogLevel.Fatal
};
Fixture.Setup($"RequestLifetime/{Lifetime}", handlerCount: 1, pipelineCount: 0);
+ BenchmarkDispatcherCacheHelper.ClearDispatcherCaches();
_baselineHandler = new BenchmarkRequestHandler();
_request = new BenchmarkRequest(Guid.NewGuid());
_container = BenchmarkHostFactory.CreateFrozenGFrameworkContainer(container =>
{
+ BenchmarkHostFactory.RegisterGeneratedBenchmarkRegistry(container);
RegisterGFrameworkHandler(container, Lifetime);
});
+ // 容器内已提前保留默认 runtime 以支撑 generated registry 接线;
+ // 这里额外创建带生命周期后缀的 runtime,只是为了区分不同 benchmark 矩阵的 dispatcher 日志。
_runtime = GFramework.Cqrs.CqrsRuntimeFactory.CreateRuntime(
_container,
LoggerFactoryResolver.Provider.CreateLogger(nameof(RequestLifetimeBenchmarks) + "." + Lifetime));
@@ -111,7 +115,14 @@ public class RequestLifetimeBenchmarks
[GlobalCleanup]
public void Cleanup()
{
- BenchmarkCleanupHelper.DisposeAll(_container, _serviceProvider);
+ try
+ {
+ BenchmarkCleanupHelper.DisposeAll(_container, _serviceProvider);
+ }
+ finally
+ {
+ BenchmarkDispatcherCacheHelper.ClearDispatcherCaches();
+ }
}
///
@@ -146,6 +157,10 @@ public class RequestLifetimeBenchmarks
///
/// 当前 benchmark 拥有并负责释放的容器。
/// 待比较的 handler 生命周期。
+ ///
+ /// 先通过 generated registry 提供静态 descriptor,再显式覆盖 handler 生命周期,
+ /// 可以把比较变量收敛到 handler 解析成本,而不是 descriptor 发现路径本身。
+ ///
private static void RegisterGFrameworkHandler(MicrosoftDiContainer container, HandlerLifetime lifetime)
{
ArgumentNullException.ThrowIfNull(container);