[IoC container, 생성자 주입] JAVA > Spring

AppConifg.java (순수자바로 설정 클래스)

public class AppConfig {

    //memberService는 AppConfig를 통해 불러낸다.
    //생성자 주입 : 생성자를 통해서 객체를 주입.
    public MemberService memberService(){
        return new MemberServiceImpl(memberRepository());
    }

    public MemberRepository memberRepository(){
        return new MemoryMemberRepository();
    }

    public OrderService orderService(){
        return new OrderServiceImpl(memberRepository(), discountPolicy());
    }

    public DiscountPolicy discountPolicy(){
        return new FixDiscountPolicy();
    }
}

1) AppConfig 자바 클래스에서 설정에 해당하는 부분을 주입한다.
2) MemberRepository를 MemmoryMemberRepository로 주입하는 것을 설정에서 확인 할 수 있다.
3) OrderService를 생성된 memberRepository에서 생성된 MemoryMemberRepository(메모리 레포지토리)로 생성한다.
4) OrderService를 discountPolicy에서 FixDiscountPolicy(정액할인정책)으로 생성한다.
5) memberRepository의 주입을 databaseRepository로 변경하면 손쉽게 레포지토리로 변경이 가능하다.
6) discountPolicy의 주입을 FixDiscountPolicy(정액할인정책) 에서 RateDiscountPolicy(비율할인정책) 로 변경이 가능하다.

MemberServiceImpl.java ( MemberService 인터페이스는 생략 )

MemberServiceImpl.java

public class MemberServiceImpl implements MemberService{

    private final MemberRepository memberRepository;

    //MemberServiceImpl 이 repository를 선택하도록 하지 않고
    //이 부분을 AppConfig에서 설정하도록 한다.
    //이렇게 설정하면, 추상화에 대해서만 의존한다. DIP를 만족한다.

    //생성자를 통해서 어떤 레포지토리를 선택할 지 정한다.
    public MemberServiceImpl(MemberRepository memberRepository){
        this.memberRepository = memberRepository;
    }

    @Override
    public void join(Member member) {
        memberRepository.save(member);
    }

    @Override
    public Member findMember(Long memberId) {
        return memberRepository.findById(memberId);
    }
}

1) 멤버에 대한 구현체는 기본적으로 join(회원가입), findMember(회원조회) 의 오버라이드로 구성되어 있으며 해당구현을 위해 memberRepository의 선언이 필요하다.
2) AppConfig가 없었다면, private final MemberRepository memberRepository = new MemoryMemberRepository(); 라는 소스가 들어가야 하지만 AppConfig가 정의됨에 따라 private final MemberRepository memberRepository; 라는 선언과MemberServiceImpl(MemberRepository memberRepository) 생성자를 선택해서 레포지토리를 선택한다.
3) 즉, MemberServiceImpl 클래스에서는 어떤 Repository를 선택할 수 없고, AppConfig.java에서 선택한다.

AppConfig.java (Spring)

Spring, AppConfig.java

@Configuration
public class AppConfig {

    //memberService는 AppConfig를 통해 불러낸다.
    //생성자 주입 : 생성자를 통해서 객체를 주입.
    @Bean
    public MemberService memberService(){
        return new MemberServiceImpl(memberRepository());
    }

    @Bean
    public MemberRepository memberRepository(){
        return new MemoryMemberRepository();
    }

    @Bean
    public OrderService orderService(){
        return new OrderServiceImpl(memberRepository(), discountPolicy());
    }

    @Bean
    public DiscountPolicy discountPolicy(){
        return new FixDiscountPolicy();
    }
}

1) 순수 자바로 되어있던 AppConfig.java를 spring 형태의 AppConfig.java로 변경한다.
2) IoC Container에 등록하기 위해, @Configuration, @Bean 어노테이션을 이용하여 설정한다.

TEST CODE (Junit5)

public class MemberServiceTest {

    MemberService memberService;

    @BeforeEach
    public void beforeEach(){

        //변경 전 (java)
        //AppConfig appConfig = new AppConfig();
        //memberService = appConfig.memberService();

        //Spring 변경 후
        ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
        memberService  = ac.getBean("memberService", MemberService.class);
    }

    @Test
    void join(){

        //given
        Member member = new Member(1L, "memberA", Grade.VIP);

        //when
        memberService.join(member);
        Member findMember = memberService.findMember(1L);
        //then
        Assertions.assertThat(member).isEqualTo(findMember);
    }
}

1) IoC컨테이너에 AppConfig으로 @Bean형식으로 등록된 서비스들을 불러온다.
2) java 코드에서는 appConfig를 생성하는 코드를 작성했지만,
3) Spring으로 AppConfig.java 설정이 변경된 후에는 AnnoTationConfigApplcationContext에 등록된 bean으로 서비스를 불러 온 후, 코드를 실행한다.

댓글

Designed by JB FACTORY