Container / Bean :: DI(IoC)

tony·2023년 4월 30일
0

Spring

목록 보기
1/1

무엇을 공부하였는가 🤔


NestJS에서의 Module을 사용하여 Controller와 Service 간의 의존관계 주입 해결과

Spring의 컨테이너를 사용한 빈들간의 의존관계 주입 해결과 다른 것 같다.

그렇다면 NestJS에서는 Providers 주입을 어떻게 한다는 거지? 😒 을 보면 알 수 있듯이, NestJS는 아래 구조처럼 구성된다.

  1. 먼저 비즈니스 로직 서비스들을 만든다.
    1. 이 때, 서비스는 싱글톤으로 형성된다.
  2. 모듈들을 통해 서비스를 컨트롤러에 주입한다. (AppConfig와 비슷하다. 서비스에 대한 의존관계를 해결해준다.)
  3. 만약 컨트롤러에서 특정 서비스를 사용하는 경우가 있다면, 직접 객체를 형성하지 않고, 모듈이 생성해준 객체를 통해 사용한다.
  4. 만약 도메인A에서 도메인B에 대해 사용해야 한다면 - 의존해야한다면 - 도메인B의 모듈을 import해온다.
    1. 도메인 B의 모듈을 import함으로서 이 모듈이 관리하는 컨트롤러와 서비스를 사용할 수 있다. ( 의존할 수 있다 )

그렇다면 Spring에서는 어떻게 빈들의 의존관계를 해결할까??

아직 깊게 공부하지 않았지만 Nest의 각 컴포넌트들에 상응하는 Spring 컴포넌트들은 아래와 같다.

NestJSSpring
ModuleApplicationContext
ControllerSpring MVC Controller 클래스 라고는 하는데…강의상으로는 그저 클래스로 보여주고 있음
ServiceBusiness Layer 클래스 라고는 하는데…강의 상으로는 비즈니스 로직을 처리하는 클래스로 보여주고 있음

아래 시퀀스를 통해 빈을 등록하고 각 객체를 주입해준다.

  1. 스프링 컨테이너 생성
  2. 스프링 빈 등록
  3. 스프링 빈 의존관계 설정

그렇다면 실제로 코드를 보면서 어떻게 빈 의존관계를 해결하는지 보자.

등록

  1. 컨테이너 클래스 앞에 @Configuration어노테이션을 붙인다.

    @Configuration
    public class AppConfig { .. }
  2. 등록할 빈을 반환해줄 메서드 앞에 @Bean 어노테이션을 붙인다.

    @Bean
    public MemberService memberService() { .. }
  3. 반환할 객체를 생성하는 메서드를 호출한다.

    // 생성자 주입에 관련된 메서드는 각 행동이 뚜렷히 보이게 리팩토링하도록 한다.
    @Bean
    public static MemoryMemberRepository memberRepository() {
      return new MemoryMemberRepository();
    }
    1. AppConfig가 조회한 빈에 대한 객체를 주입해준다.

      ⇒ 이로 인해 서비스가 호출 시, 어떤 특정 객체를 의존하지 않게 함.

      ⇒ 즉, 서비스를 사용하는 컨트롤러와 서비스 간의 직접적인 의존관계를 끊어냄

사용

  1. MemberApp.java에서 ApplicationContext인터페이스 구현체를 생성하여 컨테이너 객체를 만든다.
    1. AnnotationConfigApplicationContext클래스를 통해 생성한다.
    2. 이 객체로부터 빈을 조회한다.
  2. 등록한 빈의 이름을 사용하여 getBean함수를 통해 빈 객체를 가져온다.
    1. 이름은 등록 시에 다르게 할 수 있다.

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());
    }
}

어떻게 쓰는가 ☝️


왜 쓰는가 ❓


레퍼런스 🔍


profile
내 코드로 세상이 더 나은 방향으로 나아갈 수 있기를

0개의 댓글