Dependency Injection(DI)는 IoC기술로, 사용자 자신의 코드로 종속성을 인스턴스화하는 대신 IoC 컨테이너(NestJs 런타임 시스템)로 위임한다.
expor class UserController{
constructor(private readonly usersService : UsersService){}
}
DI는 IoC컨테이너가 직접 객체의 생명주기를 관리하는 방식이다.
A객체에서 B객체가 필요하다고 할 때 (A는 B에 의존) A클래스에는 B클래스를 생성해서 사용가능 -> 문제는 B의 구현체가 변경되었을 때 발생 -> A는 B를 직접 참조하기에 B가 변경될 떄마다 complier는 a를 다시 컴파일 해야함 -> A와 B가 class가 아니라 module이라고 하면 변경의 크기는 더 커지게 되고 complie 시간은 더 오래 걸린다. -> 이를 해결하기 위해 B에 대한 interface를 정의하고, A에는 IB타입을 이용한다 -> 하지만 interface B의 구현체를 직접 생성해야 되는 건 여전함 -> IoC의 강력함이 발휘.
export interface Person {
getName: () => string;
}
@Injectable()
export class Dexter implement Person {
getName() {
return 'Dexter';
}
}
@Injectable()
export class Jane implement Person {
getName() {
return 'Jane'
}
}
class MyApp {
private person: Person;
constructor() {
this.person = new Dexter();
}
}
class MyApp2 {
constructor (@Inject('Perso') private p: Person) {}
}
Person 객체의 관리는 IoC가 담당한다.
Person은 인터페이스이기에 Person을 실제 구현한 클래스를 module에 선언해야 객체를 생성할 수 있다.
@Module({
controllers: [UserController],
providers: [
UserService,
{
provide: 'Person',
useClass: Dexter
}
]
})
dependencies는 클래스가 동작하기 위해 필요한 서비스나 객체를 의미
Dependency injection, or DI, is a design pattern in which a class requests dependencies from external sources rather than creating them.
dependency InJection(DI)는 class가 의존성 객체를 외부에 요청하고 외부에서 인스턴스를 생성해서 주입하는 디자인 패턴
@Injectable() decorator는 이 class를 DI system에 활용하겠다는 것을 의미한다.(Angular 공식 홈페이지)
@Injectable() decorator는 UserService가 Nest IoC 컨테이너에서 관리할 수 있는 클래스임을 선언하는 메타데이터를 첨부..
@Injectable() 만일 userService에 이 데코레이터를 사용하면 다른 어떤 Nest component에서도 주입할 수 있는 provider가 된다. 별도의 scope를 지정하지 않으면 singleton 인스턴스가 됨
constructor(private userRepository: UserRepository)
NestJS는 일반적으로 Dependency Injection으로 알려진 디자인 패턴을 기반으로 구축되었다.
NestJS에서는 TypeScript 기능 덕분에 dependency이 유형별로 해결되기에 매우 쉽게 관리할 수 있다.
UserRepository를 UserService에 Dependency Injection을 하라면 contructor에 접근 제어 지시자를 활용해서 초기화를 해주면 된다.
private를 사용하면 동일한 위치에서 즉시 userRepository 멤버를 선언하고 초기화할 수 있다.
위와 같은 코드를 생성자 기반 주입 -> provider는 생성자 메서드를 통해 주입되기 때문이다.
특정한 경우 속성 기반 주입(Property-based-injection)이 유용 -> 최상위 클래스가 하나 또는 여러 프로바이더에 의존하는 경우 생성자의 하위 클래스에서 super()를 호출하여 모든 프로바이더를 전달하는 것은 매우 쉽지 않다. 이를 방지하기 위해 property 수준에서 @Inject() decorator를 사용한다.
import { UserRepository } from './../repository/user.repository';
import { PrismaService } from './../prisma/prisma.service';
import { Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';
@Module({
controllers: [UserController],
providers: [UserService, PrismaService, UserRepository],
})
export class UserModule {}
provider로 UserService, PrismaService, UserRepository를 정의하고 controller가 있으니 injection을 수행할 수 있게 service를 Nest에 등록해야 됨. @module() 데코레이터의 providers 배열에 service들을 추가해서 이를 수행한다. 이렇게 해서 NestJS는 userController class의 dependency를 해결할 수 있다.