mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-07 00:39:00 +08:00
docs(cqrs): 补充生成式 stream invoker 文档语义
- 更新 CQRS runtime 与生成器文档,补充 generated stream invoker provider / descriptor 的并列表述。 - 说明 runtime 优先消费 generated request / stream invoker 元数据,未命中时回退到既有反射 binding。 - 调整 request-only 措辞,使 reader-facing 文案与现有 generated request invoker 语义保持一致。
This commit is contained in:
parent
8d6fc74b3d
commit
98477068d6
@ -20,7 +20,7 @@
|
|||||||
- `GeWuYou.GFramework.Cqrs`
|
- `GeWuYou.GFramework.Cqrs`
|
||||||
- 默认 runtime 与业务侧常用基类。
|
- 默认 runtime 与业务侧常用基类。
|
||||||
- `GeWuYou.GFramework.Cqrs.SourceGenerators`
|
- `GeWuYou.GFramework.Cqrs.SourceGenerators`
|
||||||
- 可选。为消费端程序集生成 `ICqrsHandlerRegistry`,运行时优先走生成注册表;只有缺失、不适用,或 fallback 仍需补齐剩余 handler 时,才继续进入反射路径。
|
- 可选。为消费端程序集生成 `ICqrsHandlerRegistry`,并在可用时补充 generated request / stream invoker provider 元数据;运行时会优先消费这些编译期元数据,只有缺失、不适用,或 fallback 仍需补齐剩余 handler 时,才继续进入反射路径。
|
||||||
- `GFramework.Core`
|
- `GFramework.Core`
|
||||||
- 架构上下文中实际调用 `ICqrsRuntime`,并在模块初始化时注册 CQRS 基础设施。
|
- 架构上下文中实际调用 `ICqrsRuntime`,并在模块初始化时注册 CQRS 基础设施。
|
||||||
|
|
||||||
@ -120,13 +120,15 @@ var playerId = await this.SendAsync(new CreatePlayerCommand(new CreatePlayerInpu
|
|||||||
## 运行时行为
|
## 运行时行为
|
||||||
|
|
||||||
- 请求分发
|
- 请求分发
|
||||||
- `CqrsDispatcher` 按请求实际类型解析 `IRequestHandler<,>`,未找到处理器会抛出异常。
|
- `CqrsDispatcher` 按请求实际类型解析 `IRequestHandler<,>`,若当前程序集提供 generated request invoker provider,则会先复用对应 descriptor 中的处理器服务类型与 invoker 元数据;未命中时仍回退到既有反射 request binding 创建路径。
|
||||||
|
- 未找到处理器会抛出异常。
|
||||||
- 通知分发
|
- 通知分发
|
||||||
- 通知会分发给所有已注册 `INotificationHandler<>`;零处理器时默认静默完成。
|
- 通知会分发给所有已注册 `INotificationHandler<>`;零处理器时默认静默完成。
|
||||||
- 默认通知发布器会按容器解析顺序逐个执行处理器,并在首个处理器抛出异常时立即停止后续分发。
|
- 默认通知发布器会按容器解析顺序逐个执行处理器,并在首个处理器抛出异常时立即停止后续分发。
|
||||||
- 若容器在 runtime 创建前已显式注册 `INotificationPublisher`,默认 runtime 会复用该策略;未注册时回退到内置顺序发布器。
|
- 若容器在 runtime 创建前已显式注册 `INotificationPublisher`,默认 runtime 会复用该策略;未注册时回退到内置顺序发布器。
|
||||||
- 流式请求
|
- 流式请求
|
||||||
- 通过 `IStreamRequest<TResponse>` 和 `IStreamRequestHandler<,>` 返回 `IAsyncEnumerable<TResponse>`。
|
- 通过 `IStreamRequest<TResponse>` 和 `IStreamRequestHandler<,>` 返回 `IAsyncEnumerable<TResponse>`。
|
||||||
|
- 当消费端程序集提供 generated stream invoker provider / descriptor 后,runtime 会优先消费这组 stream invoker 元数据;未命中时仍回退到既有反射 stream binding 创建路径。
|
||||||
- 上下文注入
|
- 上下文注入
|
||||||
- 处理器基类继承 `CqrsContextAwareHandlerBase`,runtime 会在分发前注入当前 `IArchitectureContext`。
|
- 处理器基类继承 `CqrsContextAwareHandlerBase`,runtime 会在分发前注入当前 `IArchitectureContext`。
|
||||||
- 如果处理器或行为需要上下文注入,而当前 `ICqrsContext` 不是 `IArchitectureContext`,默认实现会抛出异常。
|
- 如果处理器或行为需要上下文注入,而当前 `ICqrsContext` 不是 `IArchitectureContext`,默认实现会抛出异常。
|
||||||
@ -140,6 +142,7 @@ var playerId = await this.SendAsync(new CreatePlayerCommand(new CreatePlayerInpu
|
|||||||
|
|
||||||
- 同一程序集按稳定键去重,避免重复注册。
|
- 同一程序集按稳定键去重,避免重复注册。
|
||||||
- 优先尝试消费端程序集上的 `ICqrsHandlerRegistry` 生成注册器。
|
- 优先尝试消费端程序集上的 `ICqrsHandlerRegistry` 生成注册器。
|
||||||
|
- 当生成注册器同时暴露 generated request invoker provider 或 generated stream invoker provider 时,registrar 会把对应 descriptor 元数据接线到 runtime 缓存。
|
||||||
- 生成注册器不可用或元数据损坏时,记录告警并回退到反射扫描。
|
- 生成注册器不可用或元数据损坏时,记录告警并回退到反射扫描。
|
||||||
- 当程序集声明了 `CqrsReflectionFallbackAttribute` 时,运行时会先执行生成注册器,再只补它未覆盖的 handler。
|
- 当程序集声明了 `CqrsReflectionFallbackAttribute` 时,运行时会先执行生成注册器,再只补它未覆盖的 handler。
|
||||||
- `CqrsReflectionFallbackAttribute` 现在可以多次声明,并同时承载 `Type[]` 与 `string[]` 两类 fallback 清单。
|
- `CqrsReflectionFallbackAttribute` 现在可以多次声明,并同时承载 `Type[]` 与 `string[]` 两类 fallback 清单。
|
||||||
|
|||||||
@ -165,14 +165,25 @@ protected override void OnInitialize()
|
|||||||
|
|
||||||
1. 优先读取消费端程序集上的 `CqrsHandlerRegistryAttribute`
|
1. 优先读取消费端程序集上的 `CqrsHandlerRegistryAttribute`
|
||||||
2. 存在生成注册器时优先使用 `ICqrsHandlerRegistry`
|
2. 存在生成注册器时优先使用 `ICqrsHandlerRegistry`
|
||||||
3. 生成注册器不可用或元数据异常时记录告警并回退到反射路径
|
3. 当生成注册器同时暴露 generated request invoker provider 时,runtime 会把 request/response 类型对对应的 descriptor 预先接线到 dispatcher 缓存,后续请求分发优先消费这些 generated request invoker 元数据
|
||||||
4. 当生成注册器携带 `CqrsReflectionFallbackAttribute` 元数据时,运行时会先完成生成注册器注册,再补剩余 handler
|
4. 当生成注册器同时暴露 generated stream invoker provider 时,runtime 会以同样方式优先消费 stream request 对应的 generated stream invoker descriptor;只有当前类型对未命中时,才回退到既有反射 stream binding
|
||||||
5. `CqrsReflectionFallbackAttribute` 可以同时携带 `Type[]` 和 `string[]` 两类清单;运行时会优先复用直接 `Type` 条目,只对名称条目做定向 `Assembly.GetType(...)` 查找
|
5. 生成注册器不可用或元数据异常时记录告警并回退到反射路径
|
||||||
6. 只有旧版空 marker 或生成注册器不可用时,才会回到整程序集反射扫描
|
6. 当生成注册器携带 `CqrsReflectionFallbackAttribute` 元数据时,运行时会先完成生成注册器注册,再补剩余 handler
|
||||||
7. 同一程序集按稳定键去重,避免重复注册
|
7. `CqrsReflectionFallbackAttribute` 可以同时携带 `Type[]` 和 `string[]` 两类清单;运行时会优先复用直接 `Type` 条目,只对名称条目做定向 `Assembly.GetType(...)` 查找
|
||||||
|
8. 只有旧版空 marker 或生成注册器不可用时,才会回到整程序集反射扫描
|
||||||
|
9. 同一程序集按稳定键去重,避免重复注册
|
||||||
|
|
||||||
换句话说,声明 fallback 特性本身不等于“整包反射扫描”。当前推荐理解是:生成注册器负责能静态表达的部分,fallback 只补它覆盖不到的 handler。
|
换句话说,声明 fallback 特性本身不等于“整包反射扫描”。当前推荐理解是:生成注册器负责能静态表达的部分,fallback 只补它覆盖不到的 handler。
|
||||||
|
|
||||||
|
如果你在阅读 dispatcher 行为,可以把这部分理解成两组并列能力:
|
||||||
|
|
||||||
|
- request invoker provider / descriptor
|
||||||
|
- 面向 `SendRequestAsync(...)`、`SendAsync(...)`、`SendQueryAsync(...)` 这类单次请求分发
|
||||||
|
- stream invoker provider / descriptor
|
||||||
|
- 面向 `CreateStream(...)` 触发的流式请求分发
|
||||||
|
|
||||||
|
两者的共同点都是“优先消费 generated invoker 元数据,未命中时保留既有反射绑定作为兜底”,而不是要求业务侧切换到另一套 runtime 入口。
|
||||||
|
|
||||||
`Cqrs.SourceGenerators` 的专题入口见[CQRS Handler Registry 生成器](../source-generators/cqrs-handler-registry-generator.md)。
|
`Cqrs.SourceGenerators` 的专题入口见[CQRS Handler Registry 生成器](../source-generators/cqrs-handler-registry-generator.md)。
|
||||||
|
|
||||||
## Pipeline Behavior
|
## Pipeline Behavior
|
||||||
@ -225,7 +236,7 @@ RegisterCqrsPipelineBehavior<LoggingBehavior<,>>();
|
|||||||
| `GFramework.Cqrs.Abstractions/Cqrs/` | `ICqrsRuntime`、`ICqrsHandlerRegistrar`、`IPipelineBehavior<,>`、`IRequestHandler<,>`、`Unit` | 请求、处理器和 runtime seam 的最小契约 |
|
| `GFramework.Cqrs.Abstractions/Cqrs/` | `ICqrsRuntime`、`ICqrsHandlerRegistrar`、`IPipelineBehavior<,>`、`IRequestHandler<,>`、`Unit` | 请求、处理器和 runtime seam 的最小契约 |
|
||||||
| `GFramework.Cqrs/Command` `Query` `Notification` `Request` `Extensions` | `CommandBase<TInput, TResponse>`、`QueryBase<TInput, TResponse>`、`NotificationBase<TInput>`、`RequestBase<TInput, TResponse>`、`ContextAwareCqrsExtensions` | 业务侧常用基类和上下文发送入口 |
|
| `GFramework.Cqrs/Command` `Query` `Notification` `Request` `Extensions` | `CommandBase<TInput, TResponse>`、`QueryBase<TInput, TResponse>`、`NotificationBase<TInput>`、`RequestBase<TInput, TResponse>`、`ContextAwareCqrsExtensions` | 业务侧常用基类和上下文发送入口 |
|
||||||
| `GFramework.Cqrs/Cqrs/` | `AbstractCommandHandler<,>`、`AbstractQueryHandler<,>`、`AbstractRequestHandler<,>`、`AbstractStreamCommandHandler<,>`、`AbstractStreamQueryHandler<,>`、`LoggingBehavior<,>` | 默认处理器基类、上下文注入、流式处理与行为管道 |
|
| `GFramework.Cqrs/Cqrs/` | `AbstractCommandHandler<,>`、`AbstractQueryHandler<,>`、`AbstractRequestHandler<,>`、`AbstractStreamCommandHandler<,>`、`AbstractStreamQueryHandler<,>`、`LoggingBehavior<,>` | 默认处理器基类、上下文注入、流式处理与行为管道 |
|
||||||
| `GFramework.Cqrs` 根入口与 `Internal/` | `CqrsRuntimeFactory`、`ICqrsHandlerRegistry`、`CqrsHandlerRegistryAttribute`、`CqrsReflectionFallbackAttribute`、`DefaultCqrsRegistrationService` | runtime 创建入口、generated-registry 优先级、targeted fallback 语义和程序集去重规则 |
|
| `GFramework.Cqrs` 根入口与 `Internal/` | `CqrsRuntimeFactory`、`ICqrsHandlerRegistry`、`CqrsHandlerRegistryAttribute`、`CqrsReflectionFallbackAttribute`、`ICqrsRequestInvokerProvider` | runtime 创建入口、generated-registry 优先级、request / stream invoker provider 协作点、targeted fallback 语义和程序集去重规则 |
|
||||||
| `GFramework.Cqrs.SourceGenerators/Cqrs/` | `CqrsHandlerRegistryGenerator`、`RuntimeTypeReferenceSpec`、`OrderedRegistrationKind` | 生成注册器、可直接引用类型判定、mixed fallback 发射与诊断边界 |
|
| `GFramework.Cqrs.SourceGenerators/Cqrs/` | `CqrsHandlerRegistryGenerator`、`RuntimeTypeReferenceSpec`、`OrderedRegistrationKind` | 生成注册器、可直接引用类型判定、mixed fallback 发射与诊断边界 |
|
||||||
|
|
||||||
## 继续阅读
|
## 继续阅读
|
||||||
|
|||||||
@ -6,7 +6,8 @@ description: 为消费端程序集生成 CQRS handler registry,并在需要时
|
|||||||
# CQRS Handler Registry 生成器
|
# CQRS Handler Registry 生成器
|
||||||
|
|
||||||
`GFramework.Cqrs.SourceGenerators` 会在编译期为当前业务程序集生成 `ICqrsHandlerRegistry`,让 `GFramework.Cqrs`
|
`GFramework.Cqrs.SourceGenerators` 会在编译期为当前业务程序集生成 `ICqrsHandlerRegistry`,让 `GFramework.Cqrs`
|
||||||
runtime 在注册 handlers 时优先走静态注册表,而不是先扫描整个程序集。
|
runtime 在注册 handlers 时优先走静态注册表;当运行时合同允许时,也会把 request / stream 分发可直接复用的 invoker
|
||||||
|
元数据前移到编译期,而不是总是先扫描整个程序集或在首次分发时再走反射绑定。
|
||||||
|
|
||||||
它服务的是 `Cqrs` 家族,不是独立运行时:
|
它服务的是 `Cqrs` 家族,不是独立运行时:
|
||||||
|
|
||||||
@ -27,11 +28,17 @@ runtime 在注册 handlers 时优先走静态注册表,而不是先扫描整
|
|||||||
1. 一个实现 `ICqrsHandlerRegistry` 的内部注册器类型
|
1. 一个实现 `ICqrsHandlerRegistry` 的内部注册器类型
|
||||||
2. 程序集级 `CqrsHandlerRegistryAttribute`
|
2. 程序集级 `CqrsHandlerRegistryAttribute`
|
||||||
|
|
||||||
|
当运行时暴露对应合同、且当前 handler 可被安全静态表达时,生成注册器还可以继续暴露:
|
||||||
|
|
||||||
|
- generated request invoker provider / descriptor
|
||||||
|
- generated stream invoker provider / descriptor
|
||||||
|
|
||||||
当某些 handler 不能被生成代码安全地直接引用时,还会补发:
|
当某些 handler 不能被生成代码安全地直接引用时,还会补发:
|
||||||
|
|
||||||
- 程序集级 `CqrsReflectionFallbackAttribute`
|
- 程序集级 `CqrsReflectionFallbackAttribute`
|
||||||
|
|
||||||
这意味着运行时会先使用生成注册器完成可静态表达的映射,再只对剩余类型做补扫,而不是退回整程序集盲扫。
|
这意味着运行时会先使用生成注册器完成可静态表达的映射;对 request 与 stream 分发来说,也会优先消费 generated invoker
|
||||||
|
descriptor。只有当前类型对没有 generated metadata,或 registry / fallback 无法覆盖时,才继续回到既有反射 binding 或补扫路径,而不是退回整程序集盲扫。
|
||||||
如果这些 fallback handlers 本身仍可直接引用,生成器会优先发射 `typeof(...)` 形式的 fallback 元数据;当 runtime 允许同一程序集声明多个 fallback 特性实例时,mixed 场景也会拆成 `Type` 元数据和字符串元数据两段,进一步减少 runtime 再做字符串类型名回查的成本。
|
如果这些 fallback handlers 本身仍可直接引用,生成器会优先发射 `typeof(...)` 形式的 fallback 元数据;当 runtime 允许同一程序集声明多个 fallback 特性实例时,mixed 场景也会拆成 `Type` 元数据和字符串元数据两段,进一步减少 runtime 再做字符串类型名回查的成本。
|
||||||
|
|
||||||
## 最小接入路径
|
## 最小接入路径
|
||||||
@ -78,9 +85,11 @@ RegisterCqrsHandlersFromAssemblies(
|
|||||||
|
|
||||||
1. 先读取程序集上的 `CqrsHandlerRegistryAttribute`
|
1. 先读取程序集上的 `CqrsHandlerRegistryAttribute`
|
||||||
2. 优先激活生成的 `ICqrsHandlerRegistry`
|
2. 优先激活生成的 `ICqrsHandlerRegistry`
|
||||||
3. 若生成元数据损坏、registry 不可激活,记录告警并回退到反射路径
|
3. 若生成注册器同时提供 request invoker provider / descriptor,registrar 会把这些 request invoker 元数据预先登记到 dispatcher 缓存
|
||||||
4. 若存在 `CqrsReflectionFallbackAttribute`,只补扫剩余 handler
|
4. 若生成注册器同时提供 stream invoker provider / descriptor,runtime 也会优先消费对应的 generated stream invoker 元数据;未命中时仍回退到既有反射 stream binding
|
||||||
5. 同一程序集按稳定键去重,避免重复注册
|
5. 若生成元数据损坏、registry 不可激活,记录告警并回退到反射路径
|
||||||
|
6. 若存在 `CqrsReflectionFallbackAttribute`,只补扫剩余 handler
|
||||||
|
7. 同一程序集按稳定键去重,避免重复注册
|
||||||
|
|
||||||
这个行为由 `GFramework.Cqrs.Tests/Cqrs/CqrsHandlerRegistrarTests.cs` 和
|
这个行为由 `GFramework.Cqrs.Tests/Cqrs/CqrsHandlerRegistrarTests.cs` 和
|
||||||
`GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs` 共同覆盖。
|
`GFramework.SourceGenerators.Tests/Cqrs/CqrsHandlerRegistryGeneratorTests.cs` 共同覆盖。
|
||||||
@ -91,6 +100,7 @@ RegisterCqrsHandlersFromAssemblies(
|
|||||||
|
|
||||||
- 业务程序集内 handler 数量较多
|
- 业务程序集内 handler 数量较多
|
||||||
- 想把 handler 注册路径前移到编译期
|
- 想把 handler 注册路径前移到编译期
|
||||||
|
- 想把 request / stream 分发里可静态确定的 invoker metadata 一并前移到编译期
|
||||||
- 希望冷启动阶段减少整程序集反射扫描
|
- 希望冷启动阶段减少整程序集反射扫描
|
||||||
- 需要更明确地观察“哪些 handler 走静态注册,哪些只能走 fallback”
|
- 需要更明确地观察“哪些 handler 走静态注册,哪些只能走 fallback”
|
||||||
|
|
||||||
@ -127,6 +137,7 @@ RegisterCqrsHandlersFromAssemblies(
|
|||||||
- `GFramework.Cqrs.ICqrsHandlerRegistry`
|
- `GFramework.Cqrs.ICqrsHandlerRegistry`
|
||||||
- `GFramework.Cqrs.CqrsHandlerRegistryAttribute`
|
- `GFramework.Cqrs.CqrsHandlerRegistryAttribute`
|
||||||
- `GFramework.Cqrs.CqrsReflectionFallbackAttribute`
|
- `GFramework.Cqrs.CqrsReflectionFallbackAttribute`
|
||||||
|
- `GFramework.Cqrs.ICqrsRequestInvokerProvider`
|
||||||
- `GFramework.Cqrs.SourceGenerators.Cqrs.CqrsHandlerRegistryGenerator`
|
- `GFramework.Cqrs.SourceGenerators.Cqrs.CqrsHandlerRegistryGenerator`
|
||||||
|
|
||||||
模块族入口见:
|
模块族入口见:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user