Nest는 ModuleRef
클래스를 제공하여 프로파이더의 내부 목록을 탐색하고 인젝션 토큰을 조회 키로 사용하는 모든 프로파이더에 대한 참조를 가져옵니다. ModuleRef
클래스는 정적 및 범위 프로파이더를 모두 동적으로 인스턴스화하는 방법도 제공합니다. ModuleRef
는 일반적인 방법으로 클래스에 인젝션될 수 있습니다:
//cats.service.ts
@Injectable()
export class CatsService {
constructor(private moduleRef: ModuleRef) {}
}
ModuleRef
클래스는@nestjs/core
패키지에서 import됩니다.
ModuleRef
인스턴스 (이후 모듈 참조라고 함.)는 get()
메서드를 가집니다. 이 메서드는 인젝션 토큰/클래스 이름을 사용하여 현재 모듈에 존재하는 (인스턴스화된)프로바이더, 컨트롤러 또는 인젝터블(e.g., guard, interceptor, etc.)을 조회합니다.
@Injectable()
export class CatsService implements OnModuleInit {
private appService: AppService;
constructor(private moduleRef: ModuleRef) {}
onModuleInit() {
this.appService = this.moduleRef.get(AppService);
}
}
Warning!!
get() 메서드로 스코프 프로바이더(transient or request-scoped)를 조회하면 안 됩니다.
전역 컨텍스트에서(예를 들어, 프로바이더가 다른 모듈에서 인젝션되었다면) 프로바이더를 조회하기 위해서는 { strict: false }
옵션을 get()
에 두 번째 인자로 넘겨주십시오.
this.moduleRef.get(Service, { strict: false });
스코프 프로바이더 (transient 또는 request-scoped)를 동적으로 리졸브하기 위해서는 인젝션 토큰을 인자로 넘겨주는resolve()
메서드를 사용하십시오.
@Injectable()
export class CatsService implements OnModuleInit {
private transientService: TransientService;
constructor(private moduleRef: ModuleRef) {}
async onModuleInit() {
this.transientService = await this.moduleRef.resolve(TransientService);
}
}
resolve()
메서드는 프로바이더의 DI container sub-tree로부터 고유한 프로바이더 인스턴스를 반환합니다. 각각의 서브트리는 유니크한 컨텍스트 식별자를 가집니다. 그래서 만약 이 메서드를 한 번 이상 호출하고 인스턴스 참조를 비교한다면 이 둘이 같지 않음을 확인할 것입니다.
@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()
호출을 걸쳐 단일 인스턴스를 생성하고, 이들이 동일한 생성된 DI container sub-tree를 공유하도록 보장하려면 컨텍스트 식별자를 resolve()
메서드에 전달하면 됩니다. 컨텍스트 식별자를 생성하기 위해서 ContextIdFactory
클래스를 사용하십시오. 이 클래스는 적절한 고유 식별자를 반환하는 create()
메서드를 제공합니다.
@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
패키지에서 import 됩니다.
REQUEST
providerNest 종속성 주입 시스템에 의해 인스턴스화되고 관리되지 않는 경우, 수동으로 생성된 컨텍스트 식별자(Context Identifier)인 ContextIdFactory.create()
를 사용하면 REQUEST
제공자가 정의되지 않은 DI 서브트리를 나타냅니다.
수동으로 생성된 DI sub-tree를 위해 커스텀 REQUEST
오브젝트를 등록하기 위해서, ModuleRef#registerRequestByContextId()
메서드를 다음과 같이 사용하십시오:
const contextId = ContextIdFactory.create();
this.moduleRef.registerRequestByContextId(/* YOUR_REQUEST_OBJECT */, contextId);
경우에 따라 request context 안에 있는 request-scoped 프로바이더 인스턴스를 리졸브하고 싶을 수도 있습니다. 예를 들어, CatsService
가 요청 범위로 설정되어 있고, CatsRepository
도 요청 범위 프로바이더로 표시되어 있는 경우, 동일한 DI 컨테이너 서브트리를 공유하기 위해 새로운 컨텍스트 식별자를 생성하는 대신 현재 컨텍스트 식별자를 얻어야 합니다(위에서 언급한 ContextIdFactory.create()
함수와 같이). 현재 컨텍스트 식별자를 얻으려면, @Inject()
데코레이터를 사용하여 요청 객체를 주입받는 것으로 시작하면 됩니다.
@Injectable()
export class CatsService {
constructor(
@Inject(REQUEST) private request: Record<string, unknown>,
) {}
}
이제, 요청 객체에 기반을 둔 컨텍스트 id를 생성하기 위해 ContextIdFactory
클래스의 getByRequest()
메서드를 사용하고 컨텍스트 id를 resolve()
호출에 전달하십시오:
const contextId = ContextIdFactory.getByRequest(this.request);
const catsRepository = await this.moduleRef.resolve(CatsRepository, contextId);
동적으로 이전에 프로바이더로 등록되지 않은 클래스를 인스턴스화 시키기 위해서, 모듈 참조의 create()
메서드를 사용하십시오.
@Injectable()
export class CatsService implements OnModuleInit {
private catsFactory: CatsFactory;
constructor(private moduleRef: ModuleRef) {}
async onModuleInit() {
this.catsFactory = await this.moduleRef.create(CatsFactory);
}
}
이 기법은 조건적으로 프레임워크 컨테이너 바깥의 다른 클래스를 인스턴스화 할 수 있게 해줍니다.