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

如何在Express+TypeScript中通过Inversify实现路由依赖注入

在Express+TypeScript中用Inversify管理路由控制器实例

要实现由Inversify接管控制器的实例化,替代手动创建的方式,只需按以下步骤配置:

1. 基础依赖准备

确保已安装必要依赖:

npm install inversify reflect-metadata express @types/express typescript
# 若使用Inversify Express工具库简化路由,额外安装:
npm install inversify-express-utils

在项目入口文件(如app.ts)顶部导入反射元数据:

import "reflect-metadata";

2. 定义注入标识(Types)

创建types.ts文件,用Symbol定义唯一的注入标识,避免命名冲突:

export const TYPES = {
  ProductService: Symbol.for("ProductService"),
  ProductController: Symbol.for("ProductController")
};

3. 配置Inversify容器

创建container.ts,绑定服务与控制器,让Inversify管理实例生命周期:

import { Container } from "inversify";
import { TYPES } from "./types";
import { ProductService } from "./ProductService";
import { ProductController } from "./ProductController";

const container = new Container();

// 绑定服务(示例为单例模式,可根据需求改为瞬态等)
container.bind<ProductService>(TYPES.ProductService).to(ProductService).inSingletonScope();
// 绑定控制器
container.bind<ProductController>(TYPES.ProductController).to(ProductController);

export { container };

4. 改造控制器(添加注入装饰器)

在ProductController.ts中,用@injectable()标记类,通过@inject()注入服务:

import { injectable, inject } from "inversify";
import { Request, Response } from "express";
import { ProductService } from "./ProductService";
import { TYPES } from "./types";

@injectable()
export class ProductController {
  private readonly productService: ProductService;

  // 通过构造函数注入服务
  constructor(@inject(TYPES.ProductService) productService: ProductService) {
    this.productService = productService;
  }

  // 路由处理方法
  getProducts(req: Request, res: Response) {
    const products = this.productService.getAllProducts();
    res.json(products);
  }

  getProductById(req: Request, res: Response) {
    const product = this.productService.getProductById(req.params.id);
    res.json(product);
  }
}

5. 两种路由绑定方案

方案1:自定义路由(手动从容器获取控制器)

在Router.ts中,不再手动实例化控制器,而是从Inversify容器中获取实例:

import { Router } from "express";
import { container } from "./container";
import { ProductController } from "./ProductController";
import { TYPES } from "./types";

const router = Router();
// 从容器获取控制器实例
const productController = container.get<ProductController>(TYPES.ProductController);

// 绑定路由到控制器方法
router.get("/products", (req, res) => productController.getProducts(req, res));
router.get("/products/:id", (req, res) => productController.getProductById(req, res));

export { router };

最后在app.ts中挂载路由:

import express from "express";
import { router as productRouter } from "./Router";

const app = express();
app.use(express.json());
app.use(productRouter);

app.listen(3000, () => console.log("Server running on port 3000"));

方案2:用InversifyExpressUtils自动绑定路由

如果想简化路由配置,可使用inversify-express-utils提供的装饰器自动绑定:
改造ProductController.ts:

import { injectable, inject } from "inversify";
import { controller, httpGet } from "inversify-express-utils";
import { Request, Response } from "express";
import { ProductService } from "./ProductService";
import { TYPES } from "./types";

@injectable()
@controller("/products") // 定义控制器的根路由
export class ProductController {
  private readonly productService: ProductService;

  constructor(@inject(TYPES.ProductService) productService: ProductService) {
    this.productService = productService;
  }

  @httpGet("/") // 对应 GET /products
  getProducts(req: Request, res: Response) {
    const products = this.productService.getAllProducts();
    res.json(products);
  }

  @httpGet("/:id") // 对应 GET /products/:id
  getProductById(req: Request, res: Response) {
    const product = this.productService.getProductById(req.params.id);
    res.json(product);
  }
}

然后在app.ts中初始化Inversify Express服务器:

import "reflect-metadata";
import { InversifyExpressServer } from "inversify-express-utils";
import { container } from "./container";
import express from "express";

// 必须导入控制器,让容器扫描到装饰器元数据
import "./ProductController";

const server = new InversifyExpressServer(container);

// 配置Express中间件
server.setConfig((app) => {
  app.use(express.json());
});

const app = server.build();
app.listen(3000, () => console.log("Server running on port 3000"));

关键注意事项

  • 所有需要被Inversify管理的类(服务、控制器)必须添加@injectable()装饰器
  • 确保反射元数据reflect-metadata被正确导入,否则装饰器无法生效
  • 容器绑定的生命周期(单例、瞬态等)可根据业务需求调整

内容的提问来源于stack exchange,提问作者Pankaj jha

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 05:42:44