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包中引入。
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)實例化一個之前未注冊的類作為提供者,使用模塊引用的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);
}
}
該技術允許你在框架容器之外偶然實例化一個不同的類。
更多建議: