最新要闻

广告

手机

英国房地产因利率上升陷入困境 房价正以2011年来最快速度下跌

英国房地产因利率上升陷入困境 房价正以2011年来最快速度下跌

宁夏评选出上半年10名“宁夏好人” 95后消防员因敬业奉献入选

宁夏评选出上半年10名“宁夏好人” 95后消防员因敬业奉献入选

家电

从0开发属于自己的nestjs框架的mini 版 —— Module篇

来源:博客园


(相关资料图)

在开写之前,我们看一下nestjs 关于Module 装饰器的用法:

  • 有四个参数,每个参数都是一个数组,controllers控制器,主要是路由的providers 提供给该模块用的服务imports导入的其他模块的服务或者模块exports 导出该模块中的服务
import { Module } from "@nestjs/common";@Module({  controllers: [],  providers: [],  imports:[],  exports:[],})export class AppModule {}
不出意外的无意外,我们将实现该模块的功能,在这里我们只需要三个参数即何,分别是 controllers,providers,imports, 其关键一步就是我们将结合第一篇的ioc来实现

话不多说,上代码

src\ioc-module.ts

引入ioc 核心(ioc篇实现的)

import { Container,  ClassProvider,  InjectableKey,  Provider,  Type,} from "./ioc-core";

定义常量

// 标识模块export const IS_Module_KEY = "IS_Module_KEY";// 标识模块注入的参数export const Module_Metate_Params = "Module_Metate_Params";

声明参数类型

/** * 声明模块的参数类型 */export interface Imodule {  imports?: Array>;  providers?: (Provider | Type)[]; //Array|Type>  controllers?: Type[];}

模块的装饰器实现

/** * 定义模块的装饰器 * @param option * @returns */export function Module(option?: Imodule) {  return function (target: any) {    Reflect.defineMetadata(IS_Module_KEY, true, target);    Reflect.defineMetadata(Module_Metate_Params, option, target);    return target;  };}

模块IOC 的容器

/** * 模块ioc的容器 */export class ContainerModule {  private iocInstance: Container;  constructor(entryModule?: Type) {    this.iocInstance = new Container();    entryModule && this.init(entryModule);  }    init(entryModule: Type) {    this.bindModule(entryModule);    this.iocInstance.loading();  }  /**   *   * @returns 获取标识为控制器的实例   */  public getControllerInstance() {    let result: Type[] = [];    let allInstance = this.iocInstance.getInstance();    allInstance.forEach((value: Type, key) => {      if (        typeof key === "function" &&        Reflect.getMetadata("IS_Controller_KEY", key)      ) {        result.push(value);      }    });    return result;  }  //模块绑定  public bindModule(module: Type) {    if (!Reflect.getMetadata(IS_Module_KEY, module)) {      console.log("导入的imports参数不属于模块");      return;    }    const provider = { provide: module, useClass: module };    Reflect.defineMetadata(InjectableKey, true, module);    this.iocInstance.add(provider);    this.bindLoadModule(provider);  }  private bindLoadModule(provider: ClassProvider) {    let meataData = Reflect.getMetadata(      Module_Metate_Params,      provider.useClass    );    if (!meataData) return;    /**     * 加载普通的provider     */    if (Array.isArray(meataData.providers)) {      meataData.providers.forEach((item: ClassProvider) =>        this.iocInstance.add(item)      );    }    /**     * 加载标识为控制器的provider     */    this.bindModuleLoadControllers(meataData.controllers || []);    /**     * 加载标识为模块的provider     */    if (Array.isArray(meataData.imports)) {      meataData.imports.forEach((itme: Type) => this.bindModule(itme));    }  }  /**   * 控制器注解,特殊的标记的provider   * @param providers   */  private bindModuleLoadControllers(providers: Type[]) {    if (!Array.isArray(providers)) {      return;    }    providers.forEach((itme) => {      Reflect.defineMetadata("IS_Controller_KEY", true, itme); //标志位控制器      Reflect.defineMetadata(InjectableKey, true, itme); //标志为可注入依赖      this.iocInstance.add({ provide: itme, useClass: itme });    });  }}

测试用例

import { Inject, Injectable } from "./ioc-core";import { ContainerModule, Module } from "./ioc-module";import { Type } from "./util";@Injectable()class A {  constructor(@Inject("api") private api: string /** b:number **/) {    console.log("----实例化A:");    console.log("a-api", this.api);  }  getA() {    console.log("执行到A 类的 getA 方法");    return this.api;  }}@Injectable()class B {  constructor(@Inject("AA") private a: A, @Inject("api") private api: string) {    console.log("----实例化B:");    console.log("B:insA", this.a);    console.log("B:api", this.api);  }  getB() {    return this.a.getA();  }}@Injectable()class C {  constructor(private b: B, @Inject("api") private api: string) {    console.log("----实例化C:");    console.log("C:insB", this.b);    console.log("C:api", this.api);  }  getC() {    return this.b.getB();  }}@Module({  providers: [    A,    B,    { provide: "AA", useClass: A },    { provide: "api", useValue: 123 },  ],  controllers: [C],  imports:[]})class M {}const m = new ContainerModule(M);let controllers: Array> = m.getControllerInstance();// console.log("控制器实例:", controllers);controllers.forEach((value, key) => {  console.log("控制器实例:", value, "---", key);});let c: Type = controllers[0];console.log("控制器实例c:", c, c.getC());

总结

1、ContainerModule 其实还是一个ioc ,只是通过它来进行加在不同类型的服务和递归加载模块容器2、Module 上的 controllers 参数并没有和路由实现相关的东西,本质就是一个provide 提供服务类3、下一篇,我们将两者结合起来实现最终的nestjs的终极版

关键词: