의존관계 주입 시 스프링 빈이 2개 이상 조회될 때 (feat. @Qualifier, @Primary)
@Autowired를 통해 의존관계를 주입할 때, spring은 type을 통해 적절한 구현체를 찾아 주입해준다. 이때, type이 일치하는 spring bean이 여러 개라면 어떻게 될까?
다음과 같은 error 가 난다.
NoUniqueBeanDefinitionException
하나의 matching을 기대했지만 2개가 matching 된댄다. (참 친절하다..)
해결 방법은 세 가지가 있다.
1. 의존관계 주입시 변수명을 주입할 객체와 동일하게 한다.
위와 같이 구현체의 변수명을 특정하면 스프링이 type과 match 되는 것이 여러 개일 경우 변수명을 통해 적절한 구현체를 주입해준다.
하지만 이 방법은 의존관계를 바꿀 때 클라이언트의 코드를 수정하는 것이므로 개방-폐쇄 원칙을 위반한다.
2. @Qualifier
@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy{
...
}
public OrderServiceImpl(MemberRepository memberRepository, @Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
두번째 방법은 구현체에 @Qualifier를 붙이고, 이를 주입할 때도 동일한 @Qualifier를 붙여주는 방식이다.
3. @Primary
@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy{
...
}
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
세번째 방법은 구현체에 @Primary를 붙이는 것이다. 이는 두번째 방법과 달리 의존관계를 주입할 때 annotation을 별도로 붙이지 않아도 되는 장점이 있다.
(참고)
@Primary 와 @Qualifier 가 동시에 쓰이면 어떻게 될까?
이 때는 @Qualifier가 우선순위를 갖는다. spring은 항상 좁은 범위, 프로그래머가 더 자세히 특정한 범위에 우선권을 준다.
정리하자면,
@Primary가 @Qualifier보다 편리하므로, @Primary를 우선적으로 쓰되, 사용 빈도가 적고 특수한 케이스(e.g. 보조데이터베이스 커넥션 활용)에 @Qualifier를 붙이는 것이 이상적이다.
사진, 내용 출처 : 인프런, 김영한 강사님의 '스프링 핵심 원리 - 기본편' 강좌, 강의자료