概述
本章节从源码视角剖析 silky 框架的内部工作机制,帮助有进阶需求的开发者理解框架是如何构建、如何运行的。通过了解框架的核心设计,可以更好地进行二次开发、自定义扩展和问题排查。
启动时(Startup)
应用启动阶段是框架初始化的核心过程,主要完成以下工作:
主机的构建
通过 HostBuilderExtensions.RegisterSilkyServices<T>() 完成:
- 服务引擎(
IEngine)的创建 - 配置文件的加载(
appsettings.yml、appsettings.{env}.yml、ratelimit.json等) - 模块依赖图的解析与排序
- IoC 容器(Autofac)的配置与服务注册
服务引擎
IEngine 是 silky 框架的核心调度器,负责:
- 管理模块生命周期(初始化、配置服务、启动后回调)
- 向 Autofac 容器注册模块和框架服务
- 在应用关闭时执行清理逻辑
模块的解析与执行
silky 的功能以**模块(Module)**为单位组织。启动时框架:
- 从指定的启动模块出发,递归解析所有直接/间接依赖的模块
- 按依赖顺序对模块进行拓扑排序
- 依次执行每个模块的
ConfigureServices注册服务 - HTTP 类型的模块额外执行
Configure配置中间件管道
服务及服务条目的解析
应用接口扫描与服务条目生成:
- 扫描程序集中标注了
[ServiceRoute]的接口,构建服务(Service)元数据 - 分析每个接口的方法,结合路由模板和 HTTP 动词特性,生成服务条目(ServiceEntry)信息
- 将服务条目注册到内存中的服务条目管理器(
IServiceEntryManager)
服务注册
服务启动后向注册中心发布自身的路由信息:
- 将本机 IP + RPC 端口 + 所有服务条目元数据组装为服务路由信息
- 通过分布式锁保护并发注册,防止多实例同时写入导致数据竞争
- 将服务路由信息写入注册中心(Zookeeper / Nacos / Consul)
依赖注入约定
silky 的约定式依赖注入机制:
ITransientDependency/IScopedDependency/ISingletonDependency三种标记接口DefaultDependencyRegistrar扫描程序集自动注册,无需显式AddXxx()[InjectNamed]特性支持同接口多实现的命名注入PropertiesAutowired属性注入、EngineContext.Current手动解析
RPC 服务代理
启动时为远程服务接口自动生成动态代理:
ServiceHelper.FindServiceProxyTypes()识别没有本地实现的远程服务接口Castle.DynamicProxy.ProxyGenerator.CreateInterfaceProxyWithoutTarget()创建运行时代理对象RpcClientProxyInterceptor拦截方法调用并转发到IExecutor执行- 支持
ServiceKey多实现路由透传
运行时(Runtime)
应用运行阶段处理实际的请求调用:
终结点与路由
运行时路由系统负责将请求映射到服务条目并转发执行:
- 路由表生成:启动时根据服务条目信息静态构建路由模板与 ASP.NET Core Endpoint 的映射
- 路由匹配:运行时根据
HTTP 方法 + 路径定位目标服务条目 - 参数提取:从路径参数、查询字符串、请求体中解析方法参数
- 本地/远程分发:根据目标服务是否在本实例,选择本地执行器或 RPC 远程调用
执行器调度系统
IExecutor / DefaultExecutor 是服务调用的统一入口,决定请求走本地还是远程执行路径:
- 本地/远程决策:通过
ServiceEntry.Executor委托判断目标服务是否在本实例 - 本地执行路径:
LocalInvoker→ 服务端过滤器管道 → 业务方法 - 远程执行路径:
RemoteInvoker→ Polly 策略 → DotNetty RPC → 目标实例
本地执行器与服务端过滤器
DefaultLocalExecutor 负责在本地实例执行业务方法:
- 服务端过滤器管道:
IServerFilter/IAsyncServerFilter(Auth / Action / Exception / Result) - 过滤器状态机:
ActionBegin → AuthorizationBegin → ActionInside → ResultBegin → InvokeEnd - 缓存拦截:
GetCachingIntercept/UpdateCachingIntercept/RemoveCachingIntercept - ObjectMethodExecutor:统一处理同步/异步/Task/ValueTask 返回类型
远程执行器与 RPC 调用链
DefaultRemoteExecutor 通过 DotNetty TCP 将调用请求发送到远程实例:
- Polly 策略组合:Timeout → Retry → CircuitBreaker → Fallback 四层嵌套
- 负载均衡:Polling / Random / HashAlgorithm / Appoint 四种分流策略
- 客户端过滤器管道:
IClientFilter/IAsyncClientFilter - TransportClient:UUID 关联请求响应,
TaskCompletionSource异步等待模式
RPC 服务端消息处理
DotNetty TCP 服务端监听 RPC 端口,接收并处理来自其他微服务的调用请求:
- Channel Pipeline:TLS → IdleState → LengthFieldFrame → Decoder/Encoder → ServerHandler
- 消息编解码:
TransportMessage(Id + ContentType + JSON Content) - DefaultServerMessageReceivedHandler:查找服务条目 → 解析参数 → 执行 → 构建响应
- RpcContext 附件透传:用户身份、租户、TraceId 在微服务调用链中隐式透传
服务治理
silky 通过 Polly 和 GovernanceOptions 在客户端和服务端两侧实现全面的可靠性保障:
- GovernanceOptions:统一管理超时、重试、熔断、负载均衡等参数
- 三层配置优先级:方法级特性 > 接口级特性 > 全局配置文件
- 熔断器:Closed → Open → Half-Open 状态机,防止雪崩效应
- 降级(Fallback):通过
[Fallback]特性配置兜底方法,熔断时返回默认值 - 并发保护:
MaxConcurrentHandlingCount限制单实例最大并发数
缓存拦截器
基于 AOP 的透明缓存机制,标注特性即可自动完成缓存读写:
[GetCachingIntercept]:读缓存优先,未命中再执行方法[UpdateCachingIntercept]:方法执行后更新缓存[RemoveCachingIntercept]/[RemoveMatchKeyCachingIntercept]:方法执行后删除/批量删除缓存KeyTemplate支持参数名占位符和[HashKey]属性占位符- 支持多租户隔离、用户级隔离和分布式事务中的缓存跳过
分布式事务(TCC)
TCC 模式的分布式事务支持,无需侵入底层资源:
[TccTransaction(ConfirmMethod, CancelMethod)]标注 Try 方法StarterTccTransactionHandler(发起者):PreTry → 全局 Confirm/CancelParticipantTccTransactionHandler(参与者):响应 Trying / Confirming / Canceling 三阶段- 事务上下文通过
RpcContext.Attachments在微服务间自动传播 - 持久化到 Redis,
TccTransactionRecoveryService定期补偿未完成事务
阅读指引
| 你想了解的问题 | 推荐阅读章节 |
|---|---|
| 框架启动时做了什么? | 主机的构建 |
| 模块系统如何工作? | 模块的解析与执行 |
| 服务条目如何生成? | 服务及服务条目的解析 |
| 服务如何注册到注册中心? | 服务注册 |
| 如何实现约定式依赖注入? | 依赖注入约定 |
| 远程服务接口如何变成可注入的代理? | RPC 服务代理 |
| HTTP 请求如何路由到服务条目? | 终结点与路由 |
| 请求如何决定走本地还是远程? | 执行器调度系统 |
| 本地执行和服务端过滤器如何工作? | 本地执行器与服务端过滤器 |
| RPC 调用的完整链路是什么? | 远程执行器与 RPC 调用链 |
| 服务端如何接收和处理 RPC 消息? | RPC 服务端消息处理 |
| 超时/重试/熔断/降级如何配置? | 服务治理 |
| 如何为服务方法添加透明缓存? | 缓存拦截器 |
| 如何实现跨服务的分布式事务? | 分布式事务(TCC) |
