Test코드를 작성하며 진행해보자.
스프링 빈 조회하기!
① 컨테이너에 등록된 모든 빈 조회하기
< 알게된 것 >
∨ 스프링 자동완성 축약어 iter : 존재하는 리스트에 대하여 향상된 for문을 만들어준다. (그냥for문 : itar)
∨ .getBeanDefinitionNames() : 스프링 빈 객체 이름 가져와 리스트로 만들어줌
∨ .getBean(빈 이름) : 이름을 통해 스프링빈 객체를 가져와줌. 타입지정안하면 Object로 받을 수 있나보다.
∨ .getBeanDefinition(빈 이름) : BeanDefinition객체를 반환한다.
class ApplicationContextInfoTest {
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);
}
}
}
}
호우~!
② 조회의 기본 : .getBean()
< 알게된 것 >
∨ getBean : 이름, 타입으로 조회 / 타입(인터페이스)로만 조회 / 구체타입으로만 조회 다 가능
∨ 실패 Test도 꼭 만들어야 한다! 이때 assertThrows를 사용하여 정상적으로 예외를 던지게끔 한다.
실패를 가정하고 만든 Test이기 때문에 반드시 예외가 던져져야 한다.
아래 테스트는 잘못된 작성이다.
ac.getBean("memberService", MemberService.class)를 보면, name이 "memberService"인 스프링 빈이 존재하기 때문에 아무 예외를 던지지 않는다.
∴ assertThrows 안에는 '예외가 던져지는 잘못된 경우'를 작성해야 한다.
@Test
@DisplayName("빈 이름으로 조회 X")
void findBeanByNameX() {
//ac.getBean("xxxxx", MemberService.class);
assertThrows(NoSuchBeanDefinitionException.class,
() -> ac.getBean("memberService", MemberService.class));
}
그대로 테스트해보면 아래 에러문구를 확인가능하다 ↓
org.opentest4j.AssertionFailedError:
Expected org.springframework.beans.factory.NoSuchBeanDefinitionException to be thrown, but nothing was thrown.
class ApplicationContextBasicFindTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("빈 이름으로 조회")
void findBeanByName() {
MemberService memberService = ac.getBean("memberService", MemberService.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("이름 없이 타입으로만 조회")
void findBeanByType() {
MemberService memberService = ac.getBean(MemberService.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("구체 타입으로 조회")
void findBeanName() {
MemberService memberService = ac.getBean("memberService", MemberServiceImpl.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("빈 이름으로 조회 X")
void findBeanByNameX() {
//ac.getBean("xxxxx", MemberService.class);
assertThrows(NoSuchBeanDefinitionException.class,
() -> ac.getBean("xxxxx", MemberService.class));
}
}
③ 빈 이름지정이 필요한 경우 : 동일타입 둘 이상 -> 오류 발생!
타입으로 스프링빈을 조회했을 때, 같은 타입인 스프링 빈이 존재한다면 어떻게 되나?
=> 오류가 발생한다.
아래 테스트를 한번 보자..
ㅡㅡㅡ
(참고) < 설정클래스 : SameBeanConfig >
∨ 이 테스트용도로만 쓸 config를 내부클래스로 만들어줬다 : (static) SameBeanConfig
: 마찬가지로 @Configuration, @Bean 이용하여 컨테이너가 관리하게 하자.
: 이 테스트용 설정클래스를 스프링 컨테이너에 전달해서 사용하면 된다.
new AnnotationConfigApplicationContext(SameBeanConfig.class)
타입이 동일한 두개의 저장소를 애플리케이션의 구성요소로 설정해주었다.
동일타입이 둘 이상일 때, 타입으로 검색하면 어떻게 오류가 나는지 확인하려고!
ㅡㅡㅡ
● 먼저, 컨테이너에 동일타입인 빈이 존재할 경우 어떤 Exception이 나는지 확인해보자.
public class ApplicationContextSameBeanFindTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SameBeanConfig.class);
// (참고) 실패 테스트! 이렇게 작성하면 Exception
@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();
}
}
}
테스트 결과 : NoUniqueBeanDefinitionException
org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type 'hello.core.member.MemberRepository' available:
expected single matching bean but found 2: memberRepository1,memberRepository2
앞서 이야기했듯 실패 테스트의 경우에는 assertThrows를 통해 예외를 던지도록 작성해야 한다.
∴ 아래와 같이 수정 필요
@Test
@DisplayName("타입으로 조회시 같은타입 둘 이상 -> 중복오류 발생")
void findBeanByTypeDuplicate() {
assertThrows(NoUniqueBeanDefinitionException.class,
() -> ac.getBean(MemberRepository.class));
}
추가 테스트도 작성해주자.
● 동일 타입의 빈이 여러개라서 타입으로 조회할 수 없다면, 당연히 빈 이름을 명시하면 되겠지 >v<
@Test
@DisplayName("타입으로 조회시 같은 타입이 둘 이상 있으면, 빈 이름을 지정하면 된다")
void findBeanByName() {
MemberRepository memberRepository = ac.getBean("memberRepository1", MemberRepository.class);
assertThat(memberRepository).isInstanceOf(MemberRepository.class);
}
● 특정 타입인 빈을 모두 조회할 수도 있다.
스프링 컨테이너에 getBeansOfType(타입)으로 조회하면, Map으로 해당타입 빈들을 모두 반환하준다.
- 아래와 같이 for문을 통해 key와 value를 print해주었다.
- 그리고 Map 자체도 print해보고 key, value를 확인해보기도 했다.
- assertThat으로 동일타입인 스프링빈 객체수가 2와 같은지 검증해보았다.
@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);
}
다음 학습 :
혹시.. 빈끼리 상속관계가 있을 경우 조회는 어떻게 될까요로리~~!
'web +a' 카테고리의 다른 글
싱글톤 컨테이너 (0) | 2022.07.08 |
---|---|
스프링 빈 조회 (getBean) - 상속관계인 경우 (0) | 2022.07.06 |
스프링 컨테이너 첫 이용 (0) | 2022.07.05 |
IoC/DI컨테이너 (0) | 2022.07.05 |
AppConfig 리팩터링 (+ 역할 요약) (0) | 2022.07.05 |