당니의 개발자 스토리
스프링 빈 조회 - 동일한 타입이 둘 이상 본문
스프링 빈 조회 - 동일한 타입이 둘 이상

스프링 빈으로 조회할 때 동일한 타입이 둘 이상이면 오류가 발생해요.
이걸 타입으로 조회할 때 같은 타입의 스프링 빈이 둘 이상이면 스프링이 '어? 뭘 선택해야 되지?' 곤란스러워하면서 오류가 발생하는데요. 이때는 빈 이름을 지정해주시면 됩니다.
그리고 참고로 ac.getBeansOfType()을 사용하면, 해당 타입의 모든 빈을 조회할 수 있어요.
한번 보여드릴게요.

beanfind에 ApplicationContextSameBeanFindTest 라는 테스트를 만들겠습니다.

cmd + e 해서 최근 테스트에서 위 코드를 복사 붙여넣기 하고, 타입으로 조회 시 같은 타입이 둘 이상 있으면, 중복 오류가 발생하는 경우의 test를 만들 겁니다.

이렇게 하면 될까요? 물론 해도 되긴 하는데, 지금 AppConfig.class 안에는

DiscountPolicy 타입으로는 RateDiscountPolicy 객체만 올라가있으므로 중복을 만들려면, AppConfig를 손봐야 합니다.
손대기 싫으니까 이 테스트 파일 안에다가 config 파일을 새로 만들게요.

SameBeanConfig 라는 static class를 만들겠습니다. 테스트 코드니까 여기 안에서만 쓸 거에요.
static 키워드란?

static class란?



중첩 클래스를 쓸 때 static class로 선언해주면 된다.
참고로 static 이라고 쓰면 장점이 뭔가요? 라고 질문하신 분들이 있는데, 클래스 안에다가 클래스를 썼다는 거는 SameBeanConfig는 ApplicationContextSameBeanFindTest 안에서만 쓰겠다는 거에요.
그래서 이제 @Bean을 등록해줄 겁니다.

이렇게 같은 타입이 둘 이상 있는 경우를 만들어줬습니다. 이렇게 작성하는게 잘못된 건 아닙니다.
만약에 성능을 10개를 저장하는 리포지토리와 1000개를 저장하는 리포지토리가 있다고 하면,

이렇게 파라미터로 넘겨줄 수도 있기 때문입니다. 그렇기 때문에 충분히 빈의 이름이 다르면서, 클래스 타입이 같을 수 있습니다.
그리고 나서,

얘를 MemberRepository로 바꿔주고 getBean으로 MemberRepository를 찾으면, 예외가 터진다는 거예요.

왜냐? 얘는 지금 타입만 지정했잖아요.
지금 스프링이 뜰 때,

이 SameBeanConfig만 가지고 실행하는 건데,

그럼 SameBeanConfig가 스프링 빈 2개를 등록하는데, 공교롭게 둘 다 타입이 MemberRepository 이라서, getBean에서 MemberRepository를 조회하면 2개가 튀어나오겠죠.
그럼 스프링 입장에서는 "어? 나 뭐 선택해야 되지?" 하고 예외를 터트리는 거죠. 돌려보면,

NoUniqueBeanDefinitionException 라는 예외가 터집니다. UniqueBean, 즉 고유한(한 개의) 빈만 있어야 되는데 지금 Unique 하지 않다는 거에요. 두 개가 나온거죠.

그래서 '나는 하나만 매칭되길 기대했는데 두 개가 찾아졌다.' 라고 써주는 거죠.
일단 테스트를 마저 완성시키겠습니다.

예외가 터지는 테스트니까 junit의 asserThrows로 오른쪽 로직을 실행했을 때, 왼쪽의 예외가 터진다고 보면 작성하면 됩니다.
그 다음에 테스트를 하나 더 만들어줄 겁니다.

이렇게 해놓고,
우리가 이전에는

이렇게 하면 예외가 터졌었죠. 그래서 어떻게 하냐면, getBean() 파라미터에다가 Bean 이름도 타입과 함께 지정해주면 돼요.

이렇게 지정을 해주고, 검증을 해보면 됩니다.

이렇게 하고 돌려보면,

성공입니다. 물론 더 정확하게 하려면,

이렇게 생성하는 구현체 이름을 바꾸면 되겠죠. 근데 번거로우니까 여기까지 하진 않겠습니다.
그런데 만약에 "난 그냥 얘네 둘 다 꺼내고 싶어!" 라고 할 수도 있잖아요.

그런 경우의 테스트를 하나 더 만들겠습니다. 그리고 나서,

이번에는 getBean's'로 찾는 겁니다. 타입으로 찾는 거니까,

이렇게 하면, Map으로 나옵니다. String이 Key이고, MemberRepository가 Value입니다.
String은 빈 이름이고, MemberRepository는 빈 객체겠죠.
리스트나 맵, 배열같은 경우는 반복문을 돌릴 수 있으므로, iterator로 돌리겠습니다. iter 하고 tab하고, soutv로 출력할 것들을 적어줍니다.

또 그냥 beansOfType도 통으로 출력해볼게요.
그리고 검증은 asserThat 해서

이렇게 하고 돌려보겠습니다.

잘 돌아갑니다.
자 이렇게 해서 중복인 경우에, 즉 같은 타입이 둘 이상 있을 때 해결하는 방법과 한번에 조회하는 방법을 알아봤습니다.
한 번에 조회하는 방법을 왜 설명을 드리냐면, 나중에 @Autowired 해서 자동으로 의존관계 주입할 때도 이런 기능이 다 적용이 됩니다.
다음 시간에는 상속관계, 부모와 자식 간의 관계일 때 조회가 어떻게 되는지 설명드리겠습니다.
'스프링 > 스프링 핵심 원리 - 기본편' 카테고리의 다른 글
| BeanFactory와 ApplicationContext (0) | 2024.01.21 |
|---|---|
| 스프링 빈 조회 - 상속 관계 (0) | 2024.01.21 |
| 스프링 빈 조회 - 기본 (0) | 2024.01.20 |
| 컨테이너에 등록된 모든 빈 조회 (0) | 2024.01.20 |
| 스프링 컨테이너 생성 (0) | 2024.01.20 |