You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Inversify初始化含嵌套依赖的类构造函数

InversifyJS 启动阶段初始化订阅器的正确实现方案

现有代码存在5个核心问题会导致初始化失败:

  • 需要被容器管理的类未添加@injectable()装饰器,Inversify无法识别构造函数的注入参数
  • 依赖绑定顺序错误,未遵循「底层依赖先绑定、上层服务后绑定」的原则
  • AsyncContainerModule中await AppSubscribers/await Locators属于无效写法,类本身不是Promise实例,await不会触发任何初始化逻辑
  • 构造函数内属性名拼写错误,定义的注入属性为locators,调用时写成了this._locators,会触发undefined报错
  • Inversify默认是懒加载模式,仅完成绑定不会主动实例化类,构造函数内的订阅注册逻辑永远不会执行

第一步:修正类定义的装饰器和笔误

所有需要注入依赖、或被注入到其他类的服务,都必须添加@injectable()装饰器,同时修正属性名、类型导入的笔误:

// app-subscribers.ts(原locator.ts)
import { inject, injectable } from 'inversify';
import TYPES from '@shared/di/types/types';
// 修正原代码导入类型和注入类型不匹配的笔误
import Locators from '../.Locators';
import { AfterTypeCreated } from './AfterTypeCreated';
import { logger } from '@shared/core/logger/logger';

@injectable() // 必须添加该装饰器,否则Inversify无法处理构造函数注入
export class AppSubscribers {
  constructor(
    @inject(TYPES.Locators)
    private locators: Locators
  ) {
    logger.info('SUBSCRIBER STARTED');
    // 修正原代码this._locators的笔误
    new AfterTypeCreated(this.locators);
  }
}

注意:Locators、Repository类如果存在构造函数注入,也需要添加@injectable()装饰器,注入参数用@inject标注对应标识即可。

第二步:修正容器绑定逻辑

删除无效的await类写法,按照依赖层级从下到上绑定,全局单例服务明确指定单例作用域,避免重复实例化:

// config.ts
export const bindings = new AsyncContainerModule(async (bind) => {
  // 先初始化最底层依赖:数据库连接
  await getDbConnection();

  // 按依赖层级从低到高绑定,推荐全局服务使用单例作用域
  bind<IRepository>(TYPES.IRepository).to(Repository).inSingletonScope();
  bind<Locators>(TYPES.Locators).to(Locators).inSingletonScope();
  bind<AppSubscribers>(TYPES.AppSubscribers).to(AppSubscribers).inSingletonScope();
  bind<RouterClass>(TYPES.RouterClass).to(RouterClass).inSingletonScope();
});

第三步:应用启动时主动触发实例化

容器加载完成后,主动获取AppSubscribers实例,触发构造函数执行完成订阅注册,这一步是启动初始化的核心:

// 应用启动入口文件(app.ts / index.ts)
import { Container } from 'inversify';
import { bindings } from './config';
import TYPES from '@shared/di/types/types';
import type { AppSubscribers } from './path-to-app-subscribers';

async function bootstrap() {
  const container = new Container();
  // 加载异步绑定模块
  await container.loadAsync(bindings);

  // 主动resolve实例,触发构造函数内的订阅注册逻辑
  // 单例作用域下后续重复get会返回同一实例,不会重复初始化
  container.get<AppSubscribers>(TYPES.AppSubscribers);

  // 后续执行路由初始化、服务启动等逻辑
  // const router = container.get<RouterClass>(TYPES.RouterClass);
  // router.listen(3000);
}

bootstrap();

额外注意事项

  • 禁止在类静态块中写依赖注入相关的初始化逻辑,静态块执行时机早于容器绑定完成,无法拿到注入的依赖实例
  • 如果存在多个订阅器,可以在AppSubscribers的构造函数中注入所有订阅器实例,仅需在入口resolve一次AppSubscribers即可完成全量订阅注册
  • 绑定作用域根据业务场景选择:全局唯一的服务(数据库连接、注册中心、订阅器)用inSingletonScope(),请求级别的服务用inRequestScope(),临时实例用默认的瞬态作用域即可

内容的提问来源于stack exchange,提问作者Mr X

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 17:54:25