NestJS에서의 Module을 사용하여 Controller와 Service 간의 의존관계 주입 해결과
Spring의 컨테이너를 사용한 빈들간의 의존관계 주입 해결과 다른 것 같다.
그렇다면 NestJS에서는 Providers 주입을 어떻게 한다는 거지? 😒 을 보면 알 수 있듯이, NestJS는 아래 구조처럼 구성된다.
그렇다면 Spring에서는 어떻게 빈들의 의존관계를 해결할까??
아직 깊게 공부하지 않았지만 Nest의 각 컴포넌트들에 상응하는 Spring 컴포넌트들은 아래와 같다.
NestJS | Spring |
---|---|
Module | ApplicationContext |
Controller | Spring MVC Controller 클래스 라고는 하는데…강의상으로는 그저 클래스로 보여주고 있음 |
Service | Business Layer 클래스 라고는 하는데…강의 상으로는 비즈니스 로직을 처리하는 클래스로 보여주고 있음 |
아래 시퀀스를 통해 빈을 등록하고 각 객체를 주입해준다.
그렇다면 실제로 코드를 보면서 어떻게 빈 의존관계를 해결하는지 보자.
등록
컨테이너 클래스 앞에 @Configuration
어노테이션을 붙인다.
@Configuration
public class AppConfig { .. }
등록할 빈을 반환해줄 메서드 앞에 @Bean
어노테이션을 붙인다.
@Bean
public MemberService memberService() { .. }
반환할 객체를 생성하는 메서드를 호출한다.
// 생성자 주입에 관련된 메서드는 각 행동이 뚜렷히 보이게 리팩토링하도록 한다.
@Bean
public static MemoryMemberRepository memberRepository() {
return new MemoryMemberRepository();
}
AppConfig가 조회한 빈에 대한 객체를 주입해준다.
⇒ 이로 인해 서비스가 호출 시, 어떤 특정 객체를 의존하지 않게 함.
⇒ 즉, 서비스를 사용하는 컨트롤러와 서비스 간의 직접적인 의존관계를 끊어냄
사용
MemberApp.java
에서 ApplicationContext
인터페이스 구현체를 생성하여 컨테이너 객체를 만든다.AnnotationConfigApplicationContext
클래스를 통해 생성한다.getBean
함수를 통해 빈 객체를 가져온다.AppConfig
package hello.core;
import hello.core.discount.DiscountPolicy;
import hello.core.discount.FixDiscountPolicy;
import hello.core.discount.RateDiscountPolicy;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.member.MemoryMemberRepository;
import hello.core.order.OrderService;
import hello.core.order.OrderServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
/* MemberService가 직접 어떤 구현체를 설정 X
* :: AppConfig가 그 역할 할당을 해주자
* ==> "생성자 주입"
* */
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
// 생성자 주입에 관련된 메서드는 각 행동이 뚜렷히 보이게 리팩토링하도록 한다.
@Bean
public static MemoryMemberRepository memberRepository() {
return new MemoryMemberRepository();
}
@Bean
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
// 할인정책에 대해 바꾸고 싶다면 아래 메서드 한 줄만 바꿔주면 된다.
@Bean
public DiscountPolicy discountPolicy(){
// return new FixDiscountPolicy();
return new RateDiscountPolicy();
}
}
MemberApp.java
package hello.core;
import hello.core.member.Grade;
import hello.core.member.Member;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MemberApp {
public static void main(String[] args) {
// 1.
// MemberService memberService = new MemberServiceImpl();
// 2.
// AppConfig appConfig = new AppConfig();
// MemberService memberService = appConfig.memberService();
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
/* member생성하고 join*/
Member member = new Member(1L, "memberA", Grade.VIP);
memberService.join(member);
Member findMember = memberService.findMember(1L);
System.out.println("new member = " + member.getName());
System.out.println("find member = " + findMember.getName());
}
}