본문 바로가기
Spring/spring 원리

조회되는 빈이 2개 이상이라면? + 어노테이션 직접만들기

by 킹차니 2021. 6. 20.
김영한님의 인프런 강의와 PDF를 바탕으로 정리하였습니다.
https://www.inflearn.com/courses?s=%EA%B9%80%EC%98%81%ED%95%9C

 

 

@Autowired타입으로 빈을 찾는다.

그렇다면 같은 타입의 빈 2개가 발견된다면 어떨까?

같은 타입의 FixDiscountPolicy, RateDiscountPolicy를 둘다 빈으로 등록하면 어떻게 되는지 봐보자.

RateDiscountPolicy
FixDiscountPolicy

 

 FixDiscountPolicy, RateDiscountPolicy 모두 @Component를 사용하여 자동 빈 등록되어 있는 것을 알 수 있다.

그리고 테스트를 해보면

자동 빈 등록설정을 하는 아래의 테스트가 오류가 나는데, 

아래와 같이 아주 친절한 오류 메세지가 나온다.

같은 타입의 빈 객체 두개가 발견되어 어떤 객체를 의존관계 주입에 사용해야할지 모르겠다는 것이다.

어떤 객체가 같은 타입인지도 말해주고 있다. 

물론 이때 OrderServiceImpl에서 주입되는 의존관계를 추상타입인 DiscountPolicy가 아니라 구체타입인 RateDiscountPolicy나 FixDiscountPolicy와 같은 하위타입을 받도록 하면 된다.

하지만 이는 우리가 그토록 지키자 했던

DIP: "추상화에 의존해야지, 구체화에 의존하면 안된다." 라는 객체지향 설계의 원칙을 깨트리게 한다.

그리고 위에서 보이듯이 구체화에 의존하자마자 다른 코드들이 깨지는 것을 볼 수 있다. 

이러한 이유로 다른 방법 3가지로 해결해야 한다.

 


 

이와 같은 문제의 해결방법에는 3가지가 있다.

1. @Autowired 필드 명 매칭

2. @Qualifier

3. @Primary 

 

 

1. @Autowired 필드 명 매칭

@Autowired는 입으로 매칭을 시도하고, 같은 타입의 빈이 2개 이상 존재하면 필드 이름 또는 파라미터 이름으로 매칭을 시도한다.

즉 현재처럼 DiscountPolicy를 구체화한 RateDiscountPoicy와 FixDiscountPolicy 두개가 빈으로 존재할 때, 

아래와 같이 필드 이름을 rateDiscountPolicy를 사용하는 것이다.(생성자나 수정자 메소드를 사용하여 의존관계주입을 한다면 파라미터 이름을 rateDiscountPolicy로 한다.)

 

 

2. @Qualifier

@Qualifier는 추가 구분자를 넣어주는 방법으로, 주입 시 추가적인 방법을 제공하는 것이지 빈 이름을 변경하는 것은 아니다.

만약 rateDiscountPolicy를 사용할 것이라면, 다음과 같이 클래스 위에 @Qualifier어노테이션과 지정할 이름을 넣어준다.

의존관계 주입에 사용할 RateDiscountPolicy에  @Qualifier 어노테이션과 이름을 넣어준다.

 

다음으로 위를 사용하는 OrderServiceImpl클래스를 보자.

위에서 보이는 것처럼 의존관계 주입 대상의 파라미터에 @Qualifier와 지정한 이름을 넣어준다.

 

수정자를 의존관계를 사용하는 경우 아래와 같이 작성해주면 된다.

 

 

3. @Primary 

@Primary는 같은 타입의 빈 객체들 중 우선순위를 매겨주는 방법이다. 

즉, RateDiscountPoicy와 FixDiscountPolicy 중 사용할 것을 하나 선택하여 @Primary를 넣어주면 해당 빈 객체가 우선순위로 선택된다.

위처럼 RateDiscountPoicy에 @Primary 어노테이션을 추가하였는데, 이렇게 되면 OverServiceImpl은 추상타입으로 의존관계를 주입 시 같은 타입이 두개 있어도 RateDiscountPoicy가 선택된다.

 

 


근데 @Qualifier 사용시 @Qualifier("mainDiscountPolicy")처럼 문자열을 직접 사용하는 것은 좋지 않다. (이는 여기서 뿐만 아니라, 다른 모든 코드에서도 마찬가지이다.) 

하여, 우리가 직접 어노테이션을 만들어서 사용해볼 것이다. 다음과 같은 Qualifier의 기능을 하는 MainDiscountPolicy어노테이션을 만든다. 

이제 이 어노테이션 만으로도, mainDiscountPolicy로 구분이 가능하게 된것이다. 

위와 같이 사용하면 된다.