public class ApplicationContextInfoTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("모든 빈 출력하기")
void findAllBean(){
// Spring Container안에서 관리되는 Bean들을 String array로 받아온다
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) { //iter + tab
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name = " + beanDefinitionName + "onject =" + bean);
}
}
}
//결과는 아래와 같이 나온다.

위의 getBeanDefinitionNames()를 이용하면 모든 등록된 bean들을 String array로 받아올수 있다. 그리고 for문을 이용해서 그 Array안에 있는 Bean들을 조회하면 된다. 그런데 위의 결과에서 내가 등록한 결과들 (hello.core.AppConfig도 bean으로 등록 된다) 말고도 Spring자체적으로 확장하기 위해 등록된 bean들까지 조회된다. 이것을 없애기 위해 다음과 같은 코드를 쓰면 된다.
@Test
@DisplayName("Application 빈 출력하기")
void findApplicationBean(){
// Spring Container안에서 관리되는 Bean들을 String array로 받아온다
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) { //iter + tab
BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);
if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION){
//만약 Bean의 역할이 ROLE_APPLICATION 우리가 등록한 Bean인 경우에만 출력하게 한다.
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name = " + beanDefinitionName + "onject =" + bean);
}
}
}
마찬가지로 Container에서 bean들을 뽑는건 똑같은데 역할이 우리가 등록한 bean들인 (ROLE_APPLICATION)인 경우에만 출력하게 하면 된다. 만약 스프링 자체적으로 등록한 Bean을 검색하고 싶으면 ROLE_INFRASTRUCTURE로 바꿔주면 된다.

그러나 위와같이 모든 Spring Bean을 조회할 일은 없을 것이다.
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());
//검증
Assertions.assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("이름 없이 타입으로만 조회")
void findBeanByType(){ //빈 이름은 method이름으로 조회가 가능하다
MemberService memberService = ac.getBean(MemberService.class);
System.out.println(memberService);
//검증
Assertions.assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("구체 타입으로 조회")
void findBeanByName2(){ //빈 이름은 method이름으로 조회가 가능하다
MemberService memberService = ac.getBean(MemberServiceImpl.class);
System.out.println(memberService);
//검증
Assertions.assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
}
Spring Container안에 Bean들이 저장되어 있고 그것을 getter, setter를 이용해서 위와 같이 가져올수 있다. 방법은 등록된 bean의 이름을 검색해서 가져오는 것과 이름 없이 인터페이스 타입으로 조회하는 것 그리고 구체 타입으로 조회하는 것 3가지 방법이 존재하는데 각각 장단점이 존재한다.
(타입은 동일한 타입 둘 이상이 있을때 혼란스러워하고, 구체 타입은 다형성 원리에 위배)
앞서 얘기했었지만, Type으로 조회할때, 같은 type의 빈이 존재하면 예외가 터진다.
public class ApplicationContextSameBeanFindTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SameBeanConfig.class);
@Test
@DisplayName("타입으로 조회시 같은 타입이 둘 이상 있으면, 중복 오류가 발생한다")
void findBeanByTypeDuplicate(){
MemberRepository bean = ac.getBean(MemberRepository.class);
}
@Configuration
static class SameBeanConfig{
@Bean
public MemberRepository memberRepository1(){
return new MemoryMemberRepository();
}
@Bean
public MemberRepository memberRepository2(){
return new MemoryMemberRepository();
}
}
}
org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type 'hello.core.member.MemberRepository' available: expected single matching bean but found 2: memberRepository1,memberRepository2