스프링에서 자바 객체들을 관리하는 공간을 스프링 컨테이너라고 부른다. 스프링에서 관리하는 자바 객체들을 빈(Bean)이라고 부르며, 스프링 컨테이너는 여러 빈(Bean)의 생성부터 소멸까지 개발자 대신 관리해준다.
스프링 컨테이너는 BeanFactory, ApplicationContext 로 구분해서 부르는데, BeanFactory는 빈을 관리하고 조회하는 역할만 담당한다면 ApplicationContext는 BeanFacory의 기능뿐만 아니라 다른 편리한 부가 기능까지 담당한다.
즉, BeanFactory를 직접 사용할 일은 거의 없고 대부분 부가기능이 포함된 ApplicaitonContext를 사용한다.
결론적으로 BeanFactory나 ApplicationContext 모두 스프링 컨테이너라고 부른다.
// 스프링 컨테이너 생성
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(...);
ApplicationContext
는 인터페이스로 AnnotationConfigApplicationContext
로 구현되어 있다.
// 스프링 컨테이너 생성(AppConfig.class)
ApplicaionContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
ApplicationContext
의 구현체인 AnnotationConfigApplicationContext
를 통해 스프링 컨테이너를 생성한다.Key-Value
형식처럼 빈 이름-빈 객체형식으로 Bean을 등록 및 관리한다.AppConfig.class
가 구성 정보로 지정되어 있다.AppConfig.class
에 등록된 Bean들을 스프링 빈 저장소가 어떻게 등록•관리하고 있는지 확인할 수 있다.// BeanName을 메서드 이름이 아닌, springBeanTest로 부여하기
@Bean(name="springBeanTest")
public MemberService memberservice() {
return new MemberServiceImpl(memberRepository());
}
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("모든 빈 출력하기")
void findAllBean(){
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name = " + beanDefinitionName + " object = " + bean);
}
}
@Test
@DisplayName("애플리케이션 빈 출력하기")
void findApplicationBean(){
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);
//Role ROLE_APPLICATION: 직접 등록한 애플리케이션 빈
//Role ROLE_INFRASTRUCTURE: 스프링 내부에서 사용하는 빈
if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name = " + beanDefinitionName + " object = " + bean);
}
}
}
@Test
@DisplayName("타입으로 조회시 같은 타입이 둘 이상 있으면, 빈 이름을 지정하면 된다")
void findBeanByName(){
MemberRepository memberRepository = ac.getBean("memberRepository1", MemberRepository.class);
assertThat(memberRepository).isInstanceOf(MemberRepository.class);
}
@Test
@DisplayName("특정 타입을 모두 조회하기")
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);
}
ac.getBeanDefinitionNames()
: 스프링에 등록된 모든 빈(스프링 내부 + 애플리케이션) 이름을 조회한다.ac.getBean()
: 빈 이름으로 빈 객체(인스턴스)를 조회한다. 아래 두 가지 방법으로 조회 가능!ac.getBean(빈 이름, 타입)
ac.getBean(타입)
NoUniqueBeanDefinitionException
이 발생하니 빈 이름을 함께 지정해 조회해야 된다.ac.getBeanOfType()
을 사용하자.getBeanOfType()
의 반환 타입은 Map<String, ?>NoSuchBeanDefinitionException
이 발생한다.getRole()
로 구분할 수 있다.ROLE_APPLICATION
: 애플리케이션 빈. 일반적으로 사용자가 정의한 빈ROLE_INFRASTRUCTURE
: 스프링 내부에서 사용하는 빈BeanDefinition
은 ApplicationContext
가 BeanDifinitionReader
를 통해 설정 정보들을 읽어 BeanDefiniton
인터페이스 객체로 생성해 설정 정보들을 관리한다.BeanDefinition
을 통해 Bean의 설정 정보들을 확인할 수 있고, 이를 통해 직접 등록한 애플리케이션 빈만 조회할 수 있다.AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
@Test
@DisplayName("부모 타입으로 조회시, 자식이 둘 이상 있으면, 중복 오류가 발생한다")
void findBeanByParentTypeDuplicate() {
// DiscountPolicy bean = ac.getBean(DiscountPolicy.class);
assertThrows(NoUniqueBeanDefinitionException.class, () -> ac.getBean(DiscountPolicy.class));
}
@Test
@DisplayName("부모 타입으로 조회시, 자식이 둘 이상 있으면, 빈 이름을 지정하면 된다")
void findBeanByParentTypeBeanName() {
DiscountPolicy rateDiscountPolicy = ac.getBean("rateDiscountPolicy", DiscountPolicy.class);
assertThat(rateDiscountPolicy).isInstanceOf(RateDiscountPolicy.class);
}
@Test
@DisplayName("부모 타입으로 모두 조회하기")
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));
}
}
@Test
@DisplayName("부모 타입으로 모두 조회하기 - Object")
void findAllBeanByObjectType() {
Map<String, Object> beansOfType = ac.getBeansOfType(Object.class);
for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + " value = " + beansOfType.get(key));
}
}
Object
타입으로 조회하면, 모든 스프링 빈이 조회된다.