스프링 컨테이너(Spring Container)
스프링 컨테이너는 자바 객체, 빈(Bean)의 생명 주기를 관리하며, 생성된 빈에게 추가적인 기능을 제공하는 것이다.
AppConfig.class
@Configuration
public class AppConfig {
@Bean
public MemberService memberService(){
return new MemberServiceImpl(memberRepository());
}
@Bean
public OrderService orderService(){
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
//중복을 방지하고, 역할과 구현 클래를 한 눈에 구분할 수 있다.
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
@Bean
public DiscountPolicy discountPolicy() {
//return new FixDiscountPolicy();
//할인 정책이 바뀌었다.
return new RateDiscountPolicy();
}
}

@Bean(name="myBean") 과 같이 빈 이름을 직접 부여할 수도 있지만, 빈 이름은 항상 다른 이름을 부여해야 한다. 스프링 컨테이너에 실제로 스프링 빈이 잘 등록되었는지 확인해보자.
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(AppConfig.class);
ApplicationContext 인터페이스를 스프링 컨테이너라 하며 AnnotationConfigApplicationContext는 스프링 컨테이너 인터페이스의 구현체이다. 
BeanFactory는 스프링 컨테이너의 최상위 인터페이스로 빈을 관리하고 조회하는 역할을 담당하며 getBean() 을 제공한다.
스프링 빈을 찾는 기본적인 조회 방법으로 다음과 같이 있다.
ac.getBean(빈이름, 타입)ac.getBean(타입)이를 활용하여 빈을 조회하는 테스트 코드를 작성하였다.
public class ApplicationContextBasicFindTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("빈 이름으로 조회")
void findBeanByName(){
MemberService memberService = ac.getBean("memberService", MemberService.class);
System.out.println("memberService = " + memberService);
System.out.println("memberService.getClass() = " + memberService.getClass());
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("이름 없이 타입으로만 조회")
void findBeanByType(){
MemberService memberService = ac.getBean(MemberService.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("구체 타입으로 조회")
void findBeanByName2(){
// 구현체로 확인하면 유연성이 떨어지지만 필요한 경우도 있음
MemberService memberService = ac.getBean("memberService", MemberServiceImpl.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("빈 이름으로 조회X")
void findBeanByNameX(){
//MemberService memberService = ac.getBean("xxxxx", MemberServiceImpl.class);
// ()-> 뒤의 로직 실행시, 다음과 같은 Exception 발생하는지에 대한 확인
assertThrows(NoSuchBeanDefinitionException.class,
() -> ac.getBean("xxxxx", MemberServiceImpl.class));
}
}
마지막 테스트는 조회 빈이 없는 경우 NoSuchBeanDefinitionException 예외 발생을 확인한 것이다.
이 게시물은 인프런 김영한 강사의 스프링 핵심 원리 - 기본편 을 듣고 작성하였습니다.