框架适配器
InferDI 适配器把精确的容器类型连接到框架 lifecycle。HTTP 适配器创建一个 request scope,并在框架原生位置公开它。React 适配器提供类型化 context,也可以拥有客户端创建的子 scope。
这就是适配器的全部职责。适配器只是轻薄的生命周期胶水代码:让 @inferdi/inferdi 保持零依赖的那套设计,同样把装饰器、控制器扫描、处理器参数注入和路由发现挡在内核之外。你选择接入的是框架的请求生命周期,而不是框架对依赖注入的理解。
软件包
| 软件包 | 框架 | 作用域位置 | 仅根模式 |
|---|---|---|---|
@inferdi/fastify | Fastify v5 | request.di | 支持 |
@inferdi/hono | Hono v4 | c.var.di | 不支持 |
@inferdi/koa | Koa v3 | ctx.state.di | 不支持 |
@inferdi/express | Express 5 | req.di | 不支持 |
@inferdi/elysia | Elysia v1 | context.di | 支持 |
@inferdi/react | React 19 | React context | 外部 Provider |
React 使用组件 lifecycle,而不是下面的 request lifecycle。外部 Provider 永远不会释放容器;managed ScopeProvider 在 commit 后创建子 scope,并始终释放它。参见 React 适配器。
通用生命周期契约
在作用域模式下,每个适配器对每个请求都会执行相同的步骤:
- 在请求开始时,从根容器创建作用域(
createScope,默认为root.createScope())。 - 在框架原生位置暴露作用域。Hono、Koa、Express 和 Elysia 会在 setup 前暴露。Fastify 只在 setup 成功后暴露
request.di,并在清理 setup 失败时短暂暴露。清理钩子仍能看到公开槽位,而错误处理器不会收到未完成的作用域。 - 如需在处理器运行前进行额外初始化,可使用
setupScope设置作用域。该步骤可以是异步的。 - 处理请求:路由处理器和框架的错误处理器从暴露的作用域解析服务。
- 在框架安全的完成时机释放作用域(
disposeScope,默认为scope.dispose()),除非所有权已被转移。
共享选项
| 选项 | 默认值 | 用途 |
|---|---|---|
container | 必填 | 暴露给应用的根容器。适配器从不释放它(Fastify 的可选 disposeRootOnClose 除外)。 |
createScope | root.createScope() | 构建请求作用域,并在此传入声明的请求输入。可以是异步的。 |
setupScope | 无 | 在处理器运行前执行额外初始化。可以是异步的。 |
disposeScope | scope.dispose() | 自定义清理。可以是同步或异步的。 |
autoDispose | true | 取 false,或返回 false 的谓词,将释放交给你的代码处理。 |
onDisposeError | 各适配器各自的接收端 | 接收请求作用域的释放失败:Fastify 用 request.log.error,Koa 用 ctx.app.emit('error'),其余用 console.error。 |
skipInferdiDispose(...) | — | 将某个请求标记为由应用拥有,用于流式或后台工作。 |
错误与所有权规则
- setup 失败只暴露原始错误。 如果
setupScope抛出,适配器会释放尚未构建完成的作用域并重新抛出该错误。此次清理过程中发生的清理失败会交给onDisposeError(或接收端),绝不会被聚合进所暴露的错误中。 - 失败的请求仍然会释放。
skipInferdiDispose仅在响应成功时抑制清理;错误路径无论如何都会释放。Express 是例外 —— 它的回调式中间件无法观察到一个已被处理的路由错误,因此一个被跳过且失败的 Express 请求仍归应用所有。 autoDispose: false和skipInferdiDispose会转移所有权。 此后由你的代码负责在正确的框架边界处释放作用域。- 响应产生之后发生的清理错误会被路由到接收端并吞掉。 此时响应已经发送,因此一个迟到的清理失败绝不会破坏它。
重要差异
| 适配器 | 差异 |
|---|---|
| Fastify | 在 onResponse 中释放;中止清理使用 onRequestAbort;可通过 disposeRootOnClose 选择启用根容器释放。 |
| Hono | 在 await next() 之后释放;流式辅助函数可能在流工作完成之前就返回,因此流式路由通常需要 skipInferdiDispose。 |
| Koa | 等待 Node 响应的 finish 或 close,因此普通的流式响应体不需要跳过。 |
| Express | 无法从回调式中间件检测到一个已被处理的下游路由错误;一个被跳过且失败的请求仍归应用所有。 |
| Elysia | 清理绑定到 onAfterResponse;如果该钩子从未触发,适配器就无法释放作用域所持有的资源。 |
