IoC, DI Container

스프링 빈 등록

@Configuration
public class 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(); // 정액 할인 정책
        return new RateDiscountPolicy(); // 정률 할인 정책
    }
}

스프링 컨테이너 생성 과정

public class OrderApp {

    public static void main(String[] args) {
				// 어노테이션 기반 자바 설정 파일을 통해 컨테이너 생성
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
				// XML 기반 설정 파일을 통해 컨테이너 생성
				ApplicationContext applicationContext = new GenericXmlApplicationContext("appConfig.xml");
				
				// 스프링 빈 조회
        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);
        System.out.println("order.calculatePrice = " + order.calculatePrice());
    }
}
  1. 스프링 컨테이너 생성
  2. 스프링 빈 등록
  3. 스프링 빈 의존 관계 설정

스프링 빈 조회

AnnotationConfigApplicationContext ac = 
				new AnnotationConfigApplicationContext(AppConfig.class);

@Test
@DisplayName("빈 이름으로 조회")
public void findBeanByName() throws Exception {
    MemberService memberService = ac.getBean("memberService", MemberService.class);
    Assertions.assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}

@Test
@DisplayName("이름 없이 타입으로만 조회")
public void findBeanByType() throws Exception {
    MemberService memberService = ac.getBean(MemberService.class);
    Assertions.assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}

@Test
@DisplayName("구체 타입으로 조회(지양)")
public void findBeanByName2() throws Exception {
    MemberService memberService = ac.getBean("memberService", MemberServiceImpl.class);
    Assertions.assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}

@Test
@DisplayName("이름으로 조회한 빈이 없는 경우 오류 발생")
public void findBeanByNameX() throws Exception {
    // MemberService xxxx = ac.getBean("xxxx", MemberService.class);
    org.junit.jupiter.api.Assertions.assertThrows(NoSuchBeanDefinitionException.class,
            () -> ac.getBean("xxxx", MemberService.class));
}