당니의 개발자 스토리
스프링 빈 조회 - 상속 관계 본문
스프링 빈 조회 - 상속 관계
스프링 빈 조회 상속관계인데요.

만약에 빈을 조회할 때 얘들이 의존관계가 아닌, 상속관계로 되어있어요.
예를 들어서, 제가 어떤 애를 부모 타입으로 조회했는데, 자식이 여러 개 있어요. 그럼 어떻게 될까요? 간단합니다.
스프링 빈을 조회할 때는 기본 대원칙이 부모 타입으로 조회를 하면, 부모의 자식 빈들은 다 끌려 나와요. 그래서 다 같이 조회가 돼요.
이게 나중에 뒤에 자동 의존관계 주입부터 시작해서 어떻게 되는지 고민하실 수도 있는데 고민 안 해도 돼요. 자식 타입은 그냥 다 끌려 나온다고 생각하시면 됩니다. 이게 이제 대원칙이에요.
이거 한 가지만 기억하시면 뒤에 거는 그냥 다 술술 풀리게 됩니다.
그래서 모든 Java 객체의 최고 부모인 Object type으로 조회하면, 모든 스프링 빈을 조회합니다.

그러니까 사실 이러한 클래스들도 눈에 안 보이지만,

Object를 상속하고 있는 거거든요. 자바는 기본적으로 모든 최상위 부모는 다 Object 예요.
눈에 안 보이면, extends Object 이 코드가 자동으로 들어간다고 보시면 돼요.
그림으로 쉽게 설명 하자면,

상속이든 구현이든, 이러한 부모 자식 간의 관계가 있을 때, 제가 1번 타입으로 조회를 해요.
그러면 본인 포함해서 1, 2, 3, 4, 5, 6, 7 다 나옵니다. 만약, 2번으로 조회하면 2, 4, 5번이 나오고, 3번 타입으로 조회하면, 3번과 3번의 자식인 6, 7 이렇게 3개가 나옵니다. 4번, 5번, 6번, 7번은 마지막 단에 있으니까 하나만 조회가 됩니다.
한번 테스트 코드를 짜보겠습니다.

그리고 나서, 복사 붙여넣기 하는데 파라미터로 전달할 설정 정보를 일단 비워놓고 붙여넣기 하겠습니다.

이제 @Configuration을 만들어야 하는데, 이번에도 static class로 TestConfig 라는 설정 정보를 만들겠습니다. 빈은 두 개를 등록할겁니다.

이렇게 하면, DiscountPolicy 타입으로 조회했을 때, 자식 타입인 RateDiscountPolicy와 FixDiscountPolicy가 조회될 겁니다.
여기까지 해두고 이제 하나씩 테스트를 만들겠습니다.

부모로 조회했더니, 둘이 나왔다고 칩시다.
ac.getBean(DiscountPolicy.class) 하면 어떻게 될까요?

여기서 지금 DiscountPolicy 타입이 2개가 있습니다. 그런데 DiscountPolicy이라는 부모 타입으로 조회했기 때문에, 자식 인스턴스 두 개가 다 걸려들죠. 그래서 둘 다 조회가 됩니다.
상속

interface의 구현도 "상속"의 일종이므로, 부모 자식 관계가 성립한다.
출처:
https://velog.io/@hkoo9329/%EC%9E%90%EB%B0%94-extends-implements-%EC%B0%A8%EC%9D%B4
일단 이렇게 돌려보면 오류가 납니다.

NoUniqueBeanDefinitionException 이라는 오류가 납니다. 조회되는 bean은 두 개인데, 반환 값은 bean 한 개였죠.
따라서 전에 했던 것처럼,

assertThrows 를 사용해서 예외를 던지면,

성공한 걸 볼 수 있습니다.
그럼 어떻게 하면 되나요? 당연히 빈 이름을 지정하면 되겠죠.
cmd + d로 복붙해서, getBean에다가 빈 이름을 지정해주면 됩니다.

타입은 DiscountPolicy이지만, 실제 구현 객체는 rateDiscountPolicy가 나오겠죠.
이제 검증을 해봐야죠.

우리가 검증할 rateDiscountPolicy가 RateDiscountPolicy의 인스턴스(객체)가 맞냐고 검증하는 겁니다.

잘 돌아가는 걸 볼 수 있습니다.
그 다음에 또 하나가 있습니다. 타입으로 조회 할 수 있는데, 특정 하위 타입으로 조회 하면 됩니다. 물론 안 좋은 방법입니다.

이렇게 적어 놓고, getBean 해서 하위 구현 클래스를 바로 지정하는 겁니다. 그러면 반환 객체도 한 개만 나오겠죠.

그리고 나서 assertThat 통해서 검증을 해보겠습니다.

이렇게 하고 돌려보면,

성공입니다. 왜냐면 RateDiscountPolicy는

이거 하나밖에 없기 때문입니다.
그런데 우리가 굳이

이 반환 타입을 인터페이스로 적는 이유는 뭘까요? RateDiscountPolicy로 하면 조회할 때 더 편하지 않을까요?
우리가 이렇게 반환 타입을 인터페이스로 적는 이유는 항상 말했듯이, 역할과 구현을 구분하기 위해서 입니다.
DiscountPolicy를 보고 역할을 보는거죠. 그래서 "아 얘는 DiscountPolicy이랑 관련된 애구나" 라고 보이는 거죠. 그래야 의존관계를 주입할 때도, DiscountPolicy를 의존하고 있을 거기 때문에 DiscountPolicy만 딱 보면 의존관계를 알 수 있는거죠.
이번에는 부모 타입으로 전부 다 조회를 해볼게요.
getBeansOfType을 써서, DiscountPolicy를 넘겨주면, 자식 타입까지 다 튀어나옵니다.

이렇게 하고, assertThat으로 검증해볼게요.

2개이면 성공으로 하고, 돌려보면 성공입니다.
그리고 나서, 빈 이름들을 조회해볼 건데, iter + tab 해서,

자동으로 assertThat을 통과하면 for 루프를 돌 겁니다. 돌려보면,

잘 돌아갑니다. 그런데 실제로 테스트 케이스 짤 때는 이런 출력물을 만들면 안돼요. 왜냐면 나중에는 자동 통과/실패를 시스템이 결정하게 해야 합니다. 우리가 항시 콘솔을 눈으로 보고 있을 수 없기 때문입니다.
이제 마지막으로 테스트 해볼 것은 Object 타입으로 조회하기 입니다.

이렇게 하면 전부 다 꺼내지겠죠. 이건 검증하지 말고, 그냥 바로 출력을 해볼게요.
돌려보면,

스프링에 있는 것까지 다 튀어나옵니다. 스프링에서 내부적으로 쓰는 빈까지 지금 다 튀어나오는 거예요. 스프링 안에는 여러가지 빈들이 등록이 되어 있거든요. 걔네들까지 다 딸려서 튀어 나온다고 보시면 됩니다.
왜냐면 모든 Java 객체는 Object 타입이기 때문에 그래요. 그래서 스프링 컨테이너에 스프링 빈으로 등록된 모든 java 객체가 출력되는 거예요. 당연히 우리가 등록했던 두가지도 다 나오죠.
자 이렇게 해서 스프링 빈을 조회하는 기본적인 방법들을 다 봤어요. 이정도면 알아두시면 돼요.
사실 여러분이 ApplicationContext에서 직접 getBean을 써서 조회할 일이 별로 없어요. 스프링 컨테이너가 자동으로 의존관계 주입을 해주는 걸 씁니다. 또는 AppConfig에 보면,

우리가 OrderService를 개발해요.

이 코드만 개발하고, 의존관계 주입에 대한 명시를 아예 안했죠. 왜냐면 그 부분은

여기서 적어주니까요.

그리고 여기서 지금 스프링 컨테이너를 통해서 뭔가 빈을 조회하는 코드가 있나요? 전혀 없죠.
그게 무슨 말이냐면, 실제 개발할 때는 이런 ApplicationContext에서 빈을 조회 할 일은 거의 없어요. 그런데 굳이 이걸 설명을 드린 이유는 이게 되게 기본 기능이기도 하고, 또 가끔 순수한 Java 애플리케이션에서 스프링 컨테이너를 생성해서 써야될 일이 있거든요. 그럴 때 이제 이런 거를 쓰는 거예요.
또 하나는 부모 타입으로 조회할 때 자식이 어디까지 조회가 되나, 이런 것들을 알고 계셔야 나중에 자동 의존관계 주입에서 문제없이 잘 해결할 수가 있기 때문에 설명을 쭉 드렸습니다.
자 빈을 조회하는 거는 여기서 마칠게요.
'스프링 > 스프링 핵심 원리 - 기본편' 카테고리의 다른 글
| 다양한 설정 형식 지원 - 자바 코드, XML (0) | 2024.01.22 |
|---|---|
| BeanFactory와 ApplicationContext (0) | 2024.01.21 |
| 스프링 빈 조회 - 동일한 타입이 둘 이상 (0) | 2024.01.21 |
| 스프링 빈 조회 - 기본 (0) | 2024.01.20 |
| 컨테이너에 등록된 모든 빈 조회 (0) | 2024.01.20 |