项目架构(2)-- 依赖库【reflect-metadata】【inversify】【inversify-express-utils】

之前的文章已经学习了

  1. 接口编写express 官网
  2. orm框架 prisma 官网

我们需要再学习:

  inversify + reflect-metadata 实现依赖注入   官网

  连接工具 inversify-express-utils  官网

reflect-metadata

  是一个 JavaScript 库,用于在运行时存储和读取元数据。它为 JavaScript 提供了反射功能,允许开发者在运行时获取关于对象、类、方法等的附加元数据。这个库特别在 TypeScript 中与装饰器(decorators)一起使用,来支持反射机制,从而增强代码的灵活性和可扩展性。

主要功能

  1. 元数据存储:reflect-metadata 允许你在类、方法、属性、参数等上存储元数据。这些元数据可以包含类型信息、方法信息、配置参数等,且可以在运行时通过反射读取。
  2. 反射功能:提供了读取和操作元数据的 API,允许开发者访问已经附加到类或对象上的元数据。这种反射机制对于依赖注入、自动验证等高级功能非常重要。
  3. 支持装饰器:与 TypeScript 的装饰器结合使用时,reflect-metadata 允许装饰器在运行时访问类或方法的类型信息及其他元数据,使得框架(如 Angular、NestJS)能够实现依赖注入、路由处理等功能。

主要功能 API

1.Reflect.defineMetadata

用于在对象或方法上定义元数据。

import "reflect-metadata";

class Example {
  @Reflect.metadata("key", "value")
  myMethod() {}
}

2.Reflect.getMetadata

用于从对象或方法中获取元数据。

const metadata = Reflect.getMetadata("key", Example.prototype, "myMethod");
console.log(metadata); // 输出: "value"

3.Reflect.hasMetadata

用于检查对象或方法上是否有特定的元数据。

const hasMeta = Reflect.hasMetadata("key", Example.prototype, "myMethod");
console.log(hasMeta); // 输出: true

4.Reflect.deleteMetadata

用于删除对象或方法上的元数据。

Reflect.deleteMetadata("key", Example.prototype, "myMethod");

工作原理

  • reflect-metadata 在运行时将元数据附加到目标对象上,允许开发者通过反射访问这些元数据。
  • 它本身并不会影响 TypeScript 的编译过程,但结合 emitDecoratorMetadata 选项一起使用时,可以通过装饰器访问类型信息

使用场景

依赖注入:许多框架(例如 Angular、NestJS)使用装饰器标记类或方法的元数据,反射这些元数据并自动注入依赖。

import "reflect-metadata";

function Inject(token: any) {
  return function(target: any, key: string | symbol) {
    Reflect.defineMetadata("design:type", token, target, key);
  };
}

class UserService {
  constructor() {}
}

class MyController {
  @Inject(UserService)
  userService: UserService;
}

路由和权限验证:框架可以通过装饰器为类或方法定义路由、权限要求等元数据,并在运行时根据这些元数据来执行操作。

验证与约束:通过装饰器和反射,框架能够自动验证数据模型或函数的参数类型,进行类型检查或其他验证。

日志记录与方法拦截:通过反射元数据,可以实现方法的自动记录或拦截功能(比如执行时间、参数、返回值等)。

InversifyJS

  是一个轻量级的 依赖注入(Dependency Injection, DI) 库,专门用于在 TypeScript 和 JavaScript 应用中实现 依赖注入模式。它主要用于帮助开发者更容易地管理对象的依赖关系,提高代码的可维护性、可测试性和解耦性。

核心概念:

  1. Container(容器)

    • 容器是 InversifyJS 的核心,它负责存储和管理依赖项,并通过容器来解决对象的创建和依赖注入。
  2. @injectable()

    • 这个装饰器用于标记一个类可以被 Inversify 容器管理和注入依赖。
  3. @inject()

    • 这个装饰器用于在构造函数标记需要注入的依赖对象。
  4. bind()

    • 用于将一个类或接口与其实现绑定到容器中,以便容器能够注入依赖。
import { injectable, inject, Container } from "inversify";

// 定义接口
interface IGreeter {
    greet(): string;
}

// 实现接口的类
@injectable()
class Greeter implements IGreeter {
    greet() {
        return "Hello, world!";
    }
}

// 需要注入 Greeter 服务的类
@injectable()
class User {
    private greeter: IGreeter;

    // 通过构造函数注入 Greeter 实例
    constructor(@inject(Greeter) greeter: IGreeter) {
        this.greeter = greeter;
    }

    greetUser() {
        console.log(this.greeter.greet());
    }
}

// 创建容器
const container = new Container();

// 注册 Greeter 和 User 到容器中
container.bind<IGreeter>(Greeter).to(Greeter);
container.bind<User>(User).to(User);

// 从容器中获取 User 实例
const user = container.get<User>(User);
user.greetUser();  // 输出:Hello, world!

 

inversify-express-utils

   是一个基于 InversifyJS 的库,它提供了一些工具和功能,使得你可以轻松地将 InversifyJSExpress 框架结合使用,来构建依赖注入驱动的 RESTful API 应用。

主要功能:

 

  1. 自动依赖注入:通过与 InversifyJS 配合使用,inversify-express-utils 允许你在 Express 路由中使用构造函数注入,而不需要手动管理依赖。它会自动将相关依赖注入到控制器中,使得代码更加简洁和易于维护。
  2. 创建 RESTful 路由:它为你提供了一个简单的方式来定义 Express 路由,通过装饰器来处理 HTTP 请求,并将请求处理与控制器方法关联起来。
  3. 控制器装饰器:通过 @controller@httpGet 等装饰器,inversify-express-utils 允许你使用声明式的方式来定义路由和对应的处理方法。这大大减少了传统 Express 应用中冗长的路由配置。

主要特性:

  • @controller:标记类为控制器类,表示该类将处理 HTTP 请求。
  • 路由装饰器:使用 @httpGet@httpPost@httpPut 等装饰器来简化 HTTP 请求和控制器方法之间的映射。
  • 依赖注入:依赖注入机制允许你将服务和组件注入到控制器中,减少了硬编码的依赖。

示例代码

使用 inversify-express-utils 构建一个 RESTful API:

项目目录:

 0.初始化

npm init -y 

tsc --init 

 

打开ts配置

1.安装 inversify, inversify-express-utils, express 等依赖

npm install inversify inversify-express-utils reflect-metadata

2.定义服务 /greeter/service.ts

import { injectable } from "inversify";

@injectable()
export class GreeterService {
    greet(): string {
        return "Hello from GreeterService!";
    }
}

3.创建控制器 /greeter/controller.ts

import { controller, httpGet } from "inversify-express-utils";
import { inject } from "inversify";
import { GreeterService } from "./service";


@controller("/greet")
export class GreeterController {
    constructor(@inject(GreeterService) private greeterService: GreeterService) {}

    @httpGet("/")
    public greet() {
        return this.greeterService.greet();
    }
}
4.设置容器并启动服务器 index.ts
import "reflect-metadata"; // Reflect Metadata 是必需的
import { Container } from "inversify";
import { InversifyExpressServer } from "inversify-express-utils";
import { GreeterService } from "./greeter/service";
import { GreeterController } from "./greeter/controller";
// 设置容器
const container = new Container();
container.bind(GreeterService).toSelf();
container.bind(GreeterController).toSelf();

// 创建 Express 服务器并配置 Inversify 容器
const server = new InversifyExpressServer(container);

// 启动服务器
server.build().listen(3000, () => {
    console.log("Server is running on http://localhost:3000");
});
5.运行和访问
访问 http://localhost:3000/greet ,你应该会看到:

 

 

posted @ 2025-04-01 13:53  蜗牛般庄  阅读(66)  评论(0)    收藏  举报
Title
页脚 HTML 代码