일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
- synchronized
- 일급 컬렉션
- Google OAuth
- spring security
- middleware
- builder
- OAuth 2.0
- java
- nestjs
- Volatile
- lombok
- factory
- Dependency Injection
- 일급 객체
- Spring
- Today
- Total
HJW's IT Blog
NestJS Document 알아보기 : Module 본문
Module
모듈은 @Module() 데코레이터로 주석이 달린 클래스이다. 해당 데코레이터는 메타데이터를 제공하여, Nest 가 어플리케이션 구조를 조작하는 데 사용할 수 있다.
각 어플리케이션에는 최소 하나의 루트 모듈이 존재한다. 루트 모듈은 NestJS 가 어플리케이션 그래프( 모듈 및 provider 관계와 의존성을 해결하는 내부 데이터 구조 )를 빌드하는데 사용되는 클래스이다. NestJS 에서 모듈은 구성요소를 효과적으로 조직하는 방법으로, 강력하게 권장된다. 즉 서로 관련된 기능 세트를 캡슐화 하는 아키텍쳐를 만들어 내는 것이다.
@Module 안에 하나의 객체가 전달되고, 해당 객체 안에 모듈이 필요한 속성들이 정의되어 있다.
- providers : NestJS 인젝터에 의해 생성될 서비스(providers) 이 정의된다
- controllers : 해당 모듈에서 정의된 controller 들을 명시하는 속성이다
- imports : 다른 모듈에서 내보낸 것 중 해당 모듈에서 필요한 기능을 가져오도록 한다.
- exports : 이 모듈에서 외부 모듈로 제공할 제공자들을 정의 한다.
모듈은 디폴트로 provider를 캡슐화 한다. 이 말은 쉽게 말해 현재 모듈에 직접 속하지 않거나 가져온 모듈에서 내보내지 않은 provider는 주입할 수 없다는 것이다.
Feature Moduels
NestJS에서 기능별 모듈을 사용하는것은 어플리케이션을 모듈화 하고 복잡성을 관리하는 중요한 방법중 하나이다. 예를 들어 CatService 와 CatController 가 동일한 도메인에 속하는 경우, 이 둘을 하나의 모듈로 묶는 것이 논리적이다. 이러한 과정을 통해 개발자는 명확한 경계를 설정하며, SOLID 원칙에 맞게 개발할 수 있다. 다음은 Module의 예시이다.
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Module({
controllers: [CatsController],
providers: [CatsService],
})
export class CatsModule {}
위와 같이 생성한 모듈을 루트 모듈에 가져와 사용할 수 있다.
import { Module } from '@nestjs/common';
import { CatsModule } from './cats/cats.module';
@Module({
imports: [CatsModule],
})
export class AppModule {}
Shared Modules
NestJS 에서 모듈은 기본적으로 Singleton 으로 동작하며, 여러 인스턴스간 동일한 인스턴스를 쉽게공유할 수 있다. 모든 모듈은 자동으로 공유 되는데, 일단 생성되면 다른 모듈에서도 재사용 할 수 있다. 예를 들어 CatsService 를 여러 모듈에서 공유하고 싶다면, 모듈의 exports 배열에 추가하여 이를 가능케 한다.
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Module({
controllers: [CatsController],
providers: [CatsService],
exports: [CatsService]
})
export class CatsModule {}
이제 CatsModule을 import 하는 모든 모듈에서 CatsService를 사용할 수 있으며, 동일한 인스턴스를 공유하게 된다.
왜 싱글톤을 사용할까?
만약 CatsService 를 각 모듈에 직접 등록하게 되면, 각 모듈마다 별도의 인스턴스가 생성되어 메모리 사용량이 증가하거나, 상태 불일치 등의 문제가 발생할 수 있다. 하지만, 모듈을 통해 CatsService 를 export 하게 되면 모든 모듈에서 동일한 인스턴스를 사용하게 되어, 메모리 소비를 줄이고 일관된 상태를 유지할 수 있다
Re-Export
각 모듈은 import로 가져온 모듈을 다시 내보낼 수 있다. A,B,C 모듈이 있다고 가정해 보자. A 모듈을 B 모듈에서 import 하고 C 모듈은 B 모듈을 import 한다. 이때 B 모듈이 A 모듈을 export 한다고 하면, C 모듈은 B 모듈만 import 하여도 A 모듈을 사용할 수 있게 된다.
Dependency Injection
모듈 클래스는 provider 또한 inject 할 수 있다. 하지만 circular dependency 를 막기 위해, 모듈 자체는 provider 로써 inject 될 수 없다
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Module({
controllers: [CatsController],
providers: [CatsService],
})
export class CatsModule {
constructor(private catsService: CatsService) {}
}
Global Module
매번 모듈을 import, export 하는것은 번거롭다. 이를 위해 @Global() 데코레이터를 사용해 모듈을 전역 스코프로 설정할 수 있다. 이렇게 등록된 모듈은 어플리케이션 전체에서 한번만 등록하면 되고, 모든 모듈에서 자동으로 사용할 수 있다. 하지만 일반적으로 import, export 를 통해 사용하는 것이 권장된다.
Dynamic Module
NestJS의 동적 모듈 시스템은, provider를 동적으로 등록하고 수성할 수 있게 해주는데, 이를 통해 커스터마이징 가능한 모듈을 쉽게 생성할 수 있다.
동적 모듈은 forRoot() 혹은 forRootAsync() 메서드를 사용해 정의할 수 있다.
다음 예제 코드를 살펴보자.
import { Module, DynamicModule } from '@nestjs/common';
import { createDatabaseProviders } from './database.providers';
import { Connection } from './connection.provider';
@Module({
providers: [Connection],
exports: [Connection],
})
export class DatabaseModule {
static forRoot(entities = [], options?): DynamicModule {
const providers = createDatabaseProviders(options, entities);
return {
module: DatabaseModule,
providers: providers,
exports: providers,
};
}
}
이 예제를 보면, forRoot() 메서드는 동적으로 모듈을 생성하고, 모듈, providers, exports 를 반환한다. 기본 provider로 Connection이 정의되어 있지만, forRoot() 메서드를 통해 전달된 entities 와 options 에 따라 추가 provider가 동적으로 생성되고 등록된다.
동적 모듈을 다른 모듈에서 사용할 때는 다음과 같이 forRoot() 메서드를 호출하여 설정할 수 있다.
import { Module } from '@nestjs/common';
import { DatabaseModule } from './database/database.module';
import { User } from './users/entities/user.entity';
@Module({
imports: [DatabaseModule.forRoot([User])],
})
export class AppModule {}
'NestJS' 카테고리의 다른 글
NestJS Document 알아보기 : Exception Filters (0) | 2024.10.20 |
---|---|
NestJS Document 알아보기 : Middleware (0) | 2024.10.20 |
NestJS Document 알아보기 : Providers (1) | 2024.10.19 |
NestJS Document 알아보기 : Controller (1) | 2024.10.19 |