gewuyou ea0b937705 feat(cqrs): 补充生成式 stream invoker 接缝
- 新增 stream invoker provider、descriptor 与 dispatcher/registrar 接线

- 更新 source generator 与回归测试,覆盖 generated stream invoker 发射和消费语义

- 更新 CQRS 文档与 ai-plan 恢复点,补充 stream invoker 的接入与验证记录
2026-04-30 13:26:54 +08:00

73 lines
3.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# GFramework.Cqrs.SourceGenerators
`GFramework.Cqrs.SourceGenerators` 用于在编译期为当前业务程序集生成 CQRS handler registry减少运行时程序集扫描与反射注册成本。
## 模块定位
这个包是编译期生成器,不是运行时消息或处理器库。
生成器会分析当前业务程序集中的:
- `IRequestHandler<,>`
- `INotificationHandler<>`
- `IStreamRequestHandler<,>`
并生成:
- `ICqrsHandlerRegistry` 实现
- 在运行时合同允许时,额外生成 request / stream invoker provider 与 descriptor 元数据
- 程序集级 `CqrsHandlerRegistryAttribute`
- 必要时的 `CqrsReflectionFallbackAttribute` 元数据
## 包关系
- 运行时:`GFramework.Cqrs`
- 契约层:`GFramework.Cqrs.Abstractions`
- 生成器:`GFramework.Cqrs.SourceGenerators`
不安装这个包也可以正常使用 CQRS区别只在于运行时会更多依赖反射扫描注册 handlers。
## 当前代码入口
仓库内该包的主要实现位于:
- `Cqrs/CqrsHandlerRegistryGenerator.cs`
它会在可以安全生成静态注册器时前移注册工作;对无法由生成代码直接引用的 handler则通过 reflection fallback 元数据让运行时做定向补扫,而不是整程序集盲扫。
当 fallback handler 本身仍可直接引用时,生成器会优先发射 `typeof(...)` 形式的 fallback 元数据;如果 runtime 允许同一程序集声明多个 fallback 特性实例mixed 场景也会拆成 `Type` 元数据和字符串元数据两段,进一步减少运行时按类型名回查程序集的成本。
当 runtime 同时暴露 request / stream invoker provider 契约时,生成注册器还会为可直接静态表达的 `IRequestHandler<,>`
`IStreamRequestHandler<,>` 发射对应 descriptor 与开放静态 invoker 方法,让 runtime 在首次创建 request / stream binding 时优先消费这些编译期元数据;未命中时仍保持既有反射 binding 创建语义。
## 最小接入路径
```xml
<ItemGroup>
<PackageReference Include="GeWuYou.GFramework.Cqrs" Version="x.y.z" />
<PackageReference Include="GeWuYou.GFramework.Cqrs.Abstractions" Version="x.y.z" />
<PackageReference Include="GeWuYou.GFramework.Cqrs.SourceGenerators"
Version="x.y.z"
PrivateAssets="all"
ExcludeAssets="runtime" />
</ItemGroup>
```
运行时侧仍按正常方式注册程序集:
```csharp
RegisterCqrsHandlersFromAssembly(typeof(GameArchitecture).Assembly);
```
安装生成器后,运行时会优先走生成的 registry无法静态表达的部分再走定向回退。
如果当前 runtime 合同已经包含 request / stream invoker provider seamgenerated registry 还会把这两类 invoker 元数据一并前移到编译期。
## 什么时候值得安装
- 你的业务程序集里 handler 数量较多
- 你希望缩小冷启动时的反射扫描范围
- 你需要把 handler 注册路径收束到编译期并保持可诊断
## 对应文档
- CQRS 栏目:[CQRS 文档](../docs/zh-CN/core/cqrs.md)
- 源码生成器总览:[源码生成器文档首页](../docs/zh-CN/source-generators/index.md)