↩뒤로가기

지금까지 순수한 자바 코드만으로 DI를 적용했다. 이제 스프링을 사용해 순수 자바코드를 스프링 기반으로 변경한다.

AppConfig 스프링 기반으로 변경

package hello.core;

import hello.core.discount.DiscountPolicy;
import hello.core.discount.RateDiscountPolicy;
import hello.core.member.MemberRepository;
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 {

    @Bean
    public MemberService memberService(){
        return new MemberServiceImpl(memberRepository());
    }
    /* 메소드 실행 시 MemoryMemberRepository 생성자를 매개변수로 갖는
    MemberServiceImpl 생성자를 MemberService타입으로 반환
    인터페이스를 먼저 불러오고
     */
    @Bean
    public static MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }
    /* 메소드 실행 시 MemoryMemberRepository 생성자를 만들어 MemberRepository타입으로 반환
    인터페이스의 생성자로 구현체를 리턴한다
     */

    @Bean
    public OrderService orderService(){
        return new OrderServiceImpl(memberRepository(), discountPolicy());
    } // 기존 인터페이스를 먼저 참조시킨다.

    @Bean
    public DiscountPolicy discountPolicy() {
        return new RateDiscountPolicy();
    }
    /*
    public MemberService memberService() {
        return new MemberServiceImpl(new MemoryMemberRepository());
        }
MemberService에서 바로 구현체를 연결하면, 중간 과정을 알 수 없다.
위 코드에서는 MemoryMemberRepository가 무슨 인터페이스를 구현했는지의 정보가 없다.

    public OrderService orderService() {
        return new OrderServiceImpl(
                new MemoryMemberRepository(),
                new FixDiscountPolicy());
리팩토링을 안하면 MemoryMemberRepository와 FixDiscountPolicy가 어떤 인터페이스를
구현했는지 모른다.

또한 new MemoryMemberRepository() 부분이 중복되어 구현체를 바꿔야 할 때에도 중복 작업이 예상된다.
     */

}

@Configuration을 클래스 앞에 붙여 스프링 설정을 해당 클래스에 구성한다. 각 메소드 앞에 @Bean을 붙여주면 스프링 컨테이너에 스프링 빈으로 등록된다.

MemberApp에 스프링 컨테이너 적용

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) {
//        AppConfig appConfig = new AppConfig();
//        MemberService memberService = appConfig.memberService();
//AppConfig에 정의된 내용 대로 생성자를 주입한다.
//여기서는 memory방식의 회원 저장소가 주입된 memberService 객체를 저장한다.

        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        MemberService memberService = applicationContext.getBean("memberService", MemberService.class);

        Member member = new Member(1L, "memberA", Grade.VIP);
        memberService.join(member);
        //Member객체-MemberService인터페이스-MemberServiceImpl구현객체의 join메소드-MemberRepository인터페이스-MemoryMemberRepository의 save메소드 순서로 넘어가며 실행한다.

        Member findMember = memberService.findMember(1L);
        System.out.println("new member = " + member.getName());
        System.out.println("find Member = " + findMember.getName());
    }
}

OrderApp에 스프링 컨테이너 적용

package hello.core;

import hello.core.member.Grade;
import hello.core.member.Member;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.order.Order;
import hello.core.order.OrderService;
import hello.core.order.OrderServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class OrderApp {

    public static void main(String[] args) {
//        AppConfig appConfig = new AppConfig();
//        MemberService memberService = appConfig.memberService();
//        OrderService orderService = appConfig.orderService();

        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        MemberService memberService = applicationContext.getBean("memberService", MemberService.class);
        OrderService orderService = applicationContext.getBean("orderService", OrderService.class);

        long memberId = 1L;
        Member member = new Member(memberId, "memberA", Grade.VIP);
        memberService.join(member);

        Order order = orderService.createOrder(memberId, "itemA", 20000);

        System.out.println("order = " + order);
    }

}

MemberApp과 OrderApp의 메인 메소드를 실행하면 기존과 동일한 결과가 출력된다.

스프링 컨테이너

<aside> 💡 코드가 오히려 더 복잡해진 것 같은데, 스프링 컨테이너를 사용하면 어떤 장점이 있지? → 졸라 많다.

</aside>