스프링빈은 스프링에서 자체적으로 등록해주는 빈들도 있고, 개발자가 다형성을 이용해서 동일한 타입의 여러 구체 클래스를 스프링빈으로 등록해서 사용할 수 있다.
다음과 같은 상황이 있다고 가정해보자.
OrderRepository 라는 인터페이스가 존재한다.
OrderRepository를 상속받아 각각 다른 방식으로 구현한 OrderRepositoryImpl1, OrderRepositoryImpl2가 존재한다.
개발자는 OrderRepositoryImpl1, OrderRepositoryImpl2를 스프링빈으로 등록해서 사용한다.(스프링 버전에 따라서 동일한 타입이 등록되지 않을 수 있다. 추가 설정이 필요할 수 있음.)
다형성을 활용해서 개발자는 OrderRepository 타입의 스프링빈을 사용한다.
하지만, OrderRepository 타입의 스프링빈은 2가지가 등록 되어 있다. 스프링 입장에서는 어떤 스프링빈을 가져와서 사용해야할지 몰라 에러를 내뱉는다.
이러한 상황에서 어떻게 처리해야할까?
@Primary은 스프링빈으로 등록될 구체 클래스에 지정해줄 수 있다.
즉, 동일한 타입의 스프링빈이 여러개 등록되어 있을때, 의존관계 주입시, @Primary가 지정된 스프링빈을 주입받아 사용한다.
@Qualifier는 타입 이외의 추가 구분자라고 한다. 즉, 동일한 타입의 스프링빈이 여러개 일때, 타입이 동일하면 @Qualifier를 이용해서 추가로 구분해서 의존관계주입을 한다.
간단한 사용 예시는 아래와 같다.
@Component
@Qualifier(value = "mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy
-------
public OrderServiceImpl(MemberRepository memberRepository, @Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
@Autowired를 이용해서 의존관계자동주입을 하게 되면 아래와 같은 규칙을 따른다.
일반적으로는 타입을 통해서 스프링빈을 조회하고 등록된 스프링빈이 여러개인경우, 필드 이름 또는 파라미터 이름으로 확인한다.
스프링빈은 Map, List 으로 조회도 가능하다.
아래의 코드는 동일한 타입으로 등록된 모든 스프링빈을 조회한다.
static class DiscountService{
private final Map<String, DiscountPolicy> policyMap;
private final List<DiscountPolicy> policyList;
public DiscountService(Map<String, DiscountPolicy> policyMap, List<DiscountPolicy> policyList) {
this.policyMap = policyMap;
this.policyList = policyList;
System.out.println("policyMap = " + policyMap);
System.out.println("policyList = " + policyList);
}
}
DiscountService를 스프링 빈으로 등록하면 @Autowired가 생략되었지만(생성자가 1개인 경우 생략 가능)
의존관계자동주입에 의해서 생성자를 통해서 의존관계가 자동 주입된다. 이때, DiscountPolicy 인터페이스 타입으로 등록된 모든 스프링빈이 주입된다.
policyMap = {fixDiscountPolicy=hello.core.discount.FixDiscountPolicy@14d14731, rateDiscountPolicy=hello.core.discount.RateDiscountPolicy@2eced48b}
policyList = [hello.core.discount.FixDiscountPolicy@14d14731, hello.core.discount.RateDiscountPolicy@2eced48b]
이제 모든 스프링빈이 조회된 Map이나 List에서 가져와 아래처럼 사용할 수 있다.
DiscountPolicy discountPolicy = policyMap.get(discountCode);
System.out.println("discountCode = " + discountCode);
System.out.println("discountPolicy = " + discountPolicy);
return discountPolicy.discount(member, price);
해당 포스팅은 아래의 강의를 공부 후 개인적으로 정리한 내용입니다.
김영한님의 스프링 기본편