개발일기장
ExpressJS에 inversify적용해서 객체 주입받기. 본문
https://tlqckd0.tistory.com/56
여기 마지막 부분인 아래 코드 부분을 해결하기 위해서 inversify를 사용해봤음.
routerList.push(new HelloController(new HelloService(new HelloRepository(new Map<Number, String>)), "/user"));
NodeJS에서 객체(Class)를 주입하고 관리하는것을 도와주는 패키지...고, Typescript이어야함.
일단 주입받고 주입할 객채들은 총 4가지였음 <Controller, Service, Repository, dataSoucre(Map<Number,String>) >
1. 각각의 객채를 Symbol을 통해서 정의하기
const TYPES = {
HelloController: Symbol.for("HelloController"),
HelloRepository: Symbol.for("HelloRepository"),
HelloService: Symbol.for("HelloService"),
DataSource: Symbol.for("DataSource")
}
export { TYPES }
이렇게 사용할 객체들의 이름들을 정의해둬야 나중에 필요한것을 주입받을때 사용할 수 있음.
2. inversify Container에 담기
지금까지 만들었던 객채들을 bind해주는 작업이 필요함.
container.bind<{name of class}>({type of class}).to({value of class})...{option}
1. class에는 아까 만들었던 Controller, Service 등등 Class또는 Interface로 정의된 것을 넣으면 되고
2. type에는 Symbol로 정의했던 그 값을 집어넣는다.
3. 그리고 value에는 그 실제값이 들어가면 되는다. 밑에는 name과 value가 같이 넣어놨는데(귀찮아서) 일반적으로 구현체는 직접 사용하면 확장성이나 그런면에서 불리함이 있기 때문에 interface를 name으로 넣고, value에는 class를 넣는 방식을 사용한다.
import { Container } from "inversify";
import { HelloController } from "../controller/hello.controller";
import { HelloRepository } from "../repository/hello.repository";
import { HelloService } from "../service/hello.service";
import { TYPES } from "./types";
const myContainer = new Container();
myContainer.bind<HelloService>(TYPES.HelloService).to(HelloService).inSingletonScope();
myContainer.bind<HelloController>(TYPES.HelloController).to(HelloController).inSingletonScope();
myContainer.bind<HelloRepository>(TYPES.HelloRepository).to(HelloRepository).inSingletonScope();
myContainer.bind<Map<Number, String>>(TYPES.DataSource).toConstantValue(new Map<Number, String>);
export { myContainer };
1. 끝에 inSingletonScope()를 하면 Spring처럼 싱글톤으로 구성이 됨.
2. 그리고 DataSource의 경우에는 일반적으로 DB pool을 사용하면 되겠지만, 당장은 간단하게 Map<Number,Stirng> 으로 정의했음. -> 바로 값을 집어넣고 싶으면 toConstantValue( {value} )를 집어넣으면 된다.
3. Class에 inject하기
ex) HelloRepository
import "reflect-metadata";
@injectable()
class HelloRepository {
...
constructor(@inject(TYPES.DataSource) dataSource: Map<Number, String>) {
this.dataSource = dataSource;
}
....
}
일단 import "reflect-metadata"를 해줘야한다. 그래야 런타임때에 어노테이션(@)가 적용된다.
Class위에는 @injectable()를 작성하고,
constructor에는 주입받고 싶은 값 앖에 @inject({Symbol정의한것})을 집어넣어주면 된다.
4. 직접 객체 가지고오기
위에서 작성했던 container에서 원하는 Class와 Type을 작성하면 된다.
BEFORE
routerList.push(new HelloController(new HelloService(new HelloRepository(new Map<Number, String>)), "/user"));
AFTER
const helloConrtoller = myContainer.get<HelloController>(TYPES.HelloController);
routerList.push(helloConrtoller);
훨신 깔끔해졌다.
지금까지 했던 프로젝트들 이런 방식으로 조금씩 리펙토링 해봐야할것같다.
전체코드는
https://github.com/tlqckd0/inversify-express
아직 궁금한점은
1. Nodejs에서는 원래 import(require), export(module.export)를 사용할떄 cache가 되어서 singleton이 기본적으로 적용되는것으로 봤는데 큰 차이가 있는가.? toSingleton은 어떻게 작동함?
2. toConstantValue를 사용했을떄 Singleton이 됨?
3. "reflact-metadata"가 작동하는것..
이거 찾아봐야겠다.
'node.js' 카테고리의 다른 글
영화 상영 스케줄 크롤링 peppeteer, cheerio (0) | 2023.12.02 |
---|---|
Node.JS puppeteer 병렬 웹 크롤링 (수정중) (1) | 2022.12.12 |
expressJS 를 class형식으로 실행 (0) | 2022.07.28 |
Node.js. Mysql2 Transaction작업 + template만들기 (jdbc방식) (0) | 2022.05.27 |
Node.JS 웹 크롤링으로 Promise.all 성능 비교 (수정: 이거 다 틀렸음) (0) | 2022.05.18 |