
즉, 스프링 컨테이너는 내부에 존재하는 빈의 생명주기를 관리(빈의 생성, 관리, 제거 등) 하며, 생성된 빈에게 추가적인 기능을 제공하는 것이다
// 스프링 컨테이너 생성
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
ApplicationContext, BeanFactory 를 스프링 컨테이너라 한다.BeanFactory 와 ApplicationContext에 대해서 알아보자.

BeanFactory
- 스프링 컨테이너의 최상위 인터페이스다.
- 스프링 빈을 관리하고 조회하는 역할을 담당
getBean()을 제공한다.- 지금까지 우리가 사용했던 대부분의 기능은 BeanFactory 가 제공하는 기능이다.
ApplicationContext
- BeanFactory 기능을 모두 상속받아서 제공한다.
- 애플리케이션을 개발할 때 부가기능 제공
ApplicationContext가 제공하는 부가기능

메세지소스를 활용한 국제화 기능
환경변수
애플리케이션 이벤트
편리한 리소스 조회

new AnnotationConfigApplicationContext(AppConfig.class)-> (AppConfig.class)
@Bean(name="memberServiceOne")주의사항 : Bean 이름은 항상 다른 이름을 부여해야 한다.

ac.getBeanDefinitionNames() : 스프링에 등록된 모든 빈 이름 조회ac.getBean(Type), ac.getBean("Bean_Name", Type) : 빈 이름 과 타입으로 빈 인스턴스를 조회한다.NoSuchBeanDefinitionException: No bean named 'xxxxx' availableROLE_APPLICATION : 일반적으로 사용자가 정의한 빈ROLE_INFRASTRUCTURE : 스프링이 내부에서 사용하는 빈빈 이름으로 조회
void findBeanByName() {
MemberService memberService = ac.getBean("memberService",
MemberService.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
이름 없이 타입만으로 조회
void findBeanByType() {
MemberService memberService = ac.getBean(MemberService.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
구체 타입으로 조회
void findBeanByName2() {
MemberServiceImpl memberService = ac.getBean("memberService",
MemberServiceImpl.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
빈 이름으로 조회X
void findBeanByNameX() {
Assertions.assertThrows(NoSuchBeanDefinitionException.class, () ->
ac.getBean("xxxxx", MemberService.class));
}
}
참고 : 구체 타입으로 조회하면 변경시 유연성이 저하된다.
타입으로 조회시 타입이 중복되면 오류 발생 하므로 빈 이름을 지정
void findBeanByName() {
MemberRepository memberRepository = ac.getBean("memberRepository1",
MemberRepository.class);
assertThat(memberRepository).isInstanceOf(MemberRepository.class);
}
특정 타입을 모두 조회
void findAllBeanByType() {
Map<String, MemberRepository> beansOfType = ac.getBeansOfType(MemberRepository.class);
for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + " value = " + beansOfType.get(key));
}
System.out.println("beansOfType = " + beansOfType);
assertThat(beansOfType.size()).isEqualTo(2);
}
Object 타입으로 조회하면, 모든 스프링 빈을 조회한다.특정 하위 타입을 조회
void findBeanBySubType() {
RateDiscountPolicy bean = ac.getBean(RateDiscountPolicy.class);
assertThat(bean).isInstanceOf(RateDiscountPolicy.class);
}
특정 하위 타입을 조회
void findAllBeanByParentType() {
Map<String, DiscountPolicy> beansOfType = ac.getBeansOfType(DiscountPolicy.class);
assertThat(beansOfType.size()).isEqualTo(2);
for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + " value=" + beansOfType.get(key));
}
}
스프링은 자바 코드, XML 등 다양한 설정 형식을 지원하는데, 이를 지원 할 수 있는 이유는 BeanDefinition 이라는 추상화가 있어서이다.

@Bean, <bean> 등 각각 하나씩 메타 정보를 생성하고 이를 기반으로 빈을 생성한다.Code level 에서 보자면

AnnotationConfigApplicationContext 는 AnnotatedBeanDefinitionReader 를 사용해서 AppConfig.class 를 읽고 BeanDefinition 을 생성한다.
GenericXmlApplicationContext 는 XmlBeanDefinitionReader 를 사용해서 appConfig.xml 설정 정보를 읽고 BeanDefinition 을 생성한다.
새로운 형식의 설정 정보가 추가되면, ---BeanDefinitionReader 를 만들어서 BeanDefinition 을 생성하면 된다.
<출처 : 스프링 핵심 원리 - 기본편 by 김영한>