NestJS 模塊參考

2023-09-08 14:44 更新

Nest提供了一個ModuleRef類來導航到內部提供者列表,并使用注入令牌作為查找鍵名來獲取一個引用。ModuleRef類也提供了一個動態(tài)實例化靜態(tài)和范圍的提供者的方法。ModuleRef可以通過常規(guī)方法注入到類中:

cats.service.ts
@Injectable()
export class CatsService {
  constructor(private moduleRef: ModuleRef) {}
}

ModuleRef從@nestjs/core中引入。

獲取實例

ModuleRef實例(下文稱為模塊引用) 擁有get()方法。該方法獲取一個提供者,控制器或者通過注入令牌/類名獲取一個在當前模塊中可注入對象(例如守衛(wèi)或攔截器等)。

cats.service.ts
@Injectable()
export class CatsService implements OnModuleInit {
  private service: Service;
  constructor(private moduleRef: ModuleRef) {}

  onModuleInit() {
    this.service = this.moduleRef.get(Service);
  }
}

不能通過get()方法獲取一個范圍的提供者(暫態(tài)的或者請求范圍的)。要使用下列的技術,參考這里了解更多控制范圍。

要從全局上下文獲取一個提供者(例如,如果提供者在不同模塊中注入),向get()的第二個參數(shù)傳遞{ strict: false }選項。

this.moduleRef.get(Service, { strict: false });

處理范圍提供者

要動態(tài)處理一個范圍提供者(瞬態(tài)的或請求范圍的),使用resolve()方法并將提供者的注入令牌作為參數(shù)提供給方法。

cats.service.ts
@Injectable()
export class CatsService implements OnModuleInit {
  private transientService: TransientService;
  constructor(private moduleRef: ModuleRef) {}

  async onModuleInit() {
    this.transientService = await this.moduleRef.resolve(TransientService);
  }
}

resolve()方法從其自身的注入容器樹返回一個提供者的唯一實例。每個子樹都有一個獨一無二的上下文引用。因此如果你調用該方法一次以上并進行引用比較的話,結果是不同的。

cats.service.ts
@Injectable()
export class CatsService implements OnModuleInit {
  constructor(private moduleRef: ModuleRef) {}

  async onModuleInit() {
    const transientServices = await Promise.all([
      this.moduleRef.resolve(TransientService),
      this.moduleRef.resolve(TransientService),
    ]);
    console.log(transientServices[0] === transientServices[1]); // false
  }
}

要在不同的resolve()調用之間產(chǎn)生一個單例,并保證他們共享同樣生成的DI容器子樹,向resolve()方法傳遞一個上下文引用,使用ContextIdFactory類來生成上下文引用。該類提供了一個create()方法,返回一個合適的獨一無二的引用。

cats.service.ts
@Injectable()
export class CatsService implements OnModuleInit {
  constructor(private moduleRef: ModuleRef) {}

  async onModuleInit() {
    const contextId = ContextIdFactory.create();
    const transientServices = await Promise.all([
      this.moduleRef.resolve(TransientService, contextId),
      this.moduleRef.resolve(TransientService, contextId),
    ]);
    console.log(transientServices[0] === transientServices[1]); // true
  }
}

ContextIdFactory類從@nestjs/core包中引入。

注冊REQUEST提供者

Manually generated context identifiers (with ContextIdFactory.create()) represent DI sub-trees in which REQUEST provider is undefined as they are not instantiated and managed by the Nest dependency injection system.

To register a custom REQUEST object for a manually created DI sub-tree, use the ModuleRef#registerRequestByContextId() method, as follows:

const contextId = ContextIdFactory.create();
this.moduleRef.registerRequestByContextId(/* YOUR_REQUEST_OBJECT */, contextId);

獲取當前子樹

有時,也需要在請求上下文中獲取一個請求范圍提供者的實例。例如,CatsService是請求范圍的,要獲取的CatsRepository實例也被標識為請求范圍。要分享同一個注入容器子樹,你需要獲取當前上下文引用而不是生成一個新的(像前面的ContextIdFactory.create()函數(shù))。使用@Inject()來獲取當前的請求對象。

cats.service.ts
@Injectable()
export class CatsService {
  constructor(
    @Inject(REQUEST) private request: Record<string, unknown>,
  ) {}
}

這里了解更多請求提供者

使用ContextIdFactory類的getByRequest()方法來基于請求對象創(chuàng)建一個上下文id 并傳遞resolve()調用:

const contextId = ContextIdFactory.getByRequest(this.request);
const catsRepository = await this.moduleRef.resolve(CatsRepository, contextId);

動態(tài)實例化自定義類

要動態(tài)實例化一個之前未注冊的類作為提供者,使用模塊引用的create()方法。

cats.service.ts
@Injectable()
export class CatsService implements OnModuleInit {
  private catsFactory: CatsFactory;
  constructor(private moduleRef: ModuleRef) {}

  async onModuleInit() {
    this.catsFactory = await this.moduleRef.create(CatsFactory);
  }
}

該技術允許你在框架容器之外偶然實例化一個不同的類。


以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號