스프링 핵심원리 기본편 - 섹션7. 의존관계 자동주입 - 조회할 빈이 2개 이상일 때 - 문제
@Autowired는 타입으로 조회한다.
@Component
public class FixDiscountPolicy implements DiscountPolicy {}
@Component
public class RateDiscountPolicy implements DiscountPolicy {}
이전에는 FixDiscountPolicy에만 @Component를 붙여 빈으로 등록시켰지만 테스트를 위해 RateDiscountPolicy도 @Component를 붙여 빈으로 등록시킴.
@Component
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
FixDiscountPolicy, RateDiscountPolicy 모두 스프링 빈에 등록됐을 때 의존관계 자동주입을 실행하면 NoUniqueBeanDefinitionException 오류 발생!
@Autowired는 타입으로 조회하는데 DiscountPolicy타입이 2개발견됨 -> FixDiscountPolicy, RateDiscountPolicy
하위타입으로 지정할 수도 있지만, 이렇게하면 DIP위반하게되고 유연성 떨어짐.
이럴땐 어떻게 해야할까? 해결방법3가지가 있다.
해결방법 3가지
1. @Autowired 필드 명 매칭
2. @Qualifier -> @Qualifier끼리 매칭 -> 빈 이름 매칭
3. @Primary 사용
@Autowired 는 타입 매칭을 시도하고, 이때 여러 빈이 있으면 필드 이름, 파라미터 이름으로 빈 이름을 추가 매칭한다.1️⃣ 타입매칭
2️⃣ 결과가2개 이상일 때 필드명, 파라미터 명으로 빈 이름 매칭
필드 명을 빈 이름으로 변경
discountPolicy -> rateDiscountPolicy
@Component
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy rateDiscountPolicy;
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.rateDiscountPolicy = discountPolicy;
}
1️⃣ @Qualifier끼리 매칭
2️⃣ 빈 이름 매칭
3️⃣ NoSuchBeanDefinitionException 예외 발생
빈 등록시 @Qualifier를 붙여 준다.
@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
@Qualifier("fixDiscountPolicy")
public class FixDiscountPolicy implements DiscountPolicy {}
생성자 자동 주입 예시 )
@Component
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, @Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
수정자 자동 주입 예시 )
@Autowired
public DiscountPolicy setDiscountPolicy(@Qualifier("mainDiscountPolicy")
DiscountPolicy discountPolicy) {
this.discountPolicy = discountPolicy;
}
@Qualifier 로 주입할 때 @Qualifier("mainDiscountPolicy") 를 못찾으면 어떻게 될까?@Qualifier 는 @Qualifier 를 찾 는 용도로만 사용하는게 명확하고 좋다. //RateDiscountPolicy가 우선권을 갖음
@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
public class FixDiscountPolicy implements DiscountPolicy {}
//생성자
@Autowired
public OrderServiceImpl(MemberRepository memberRepository,
DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
//수정자
@Autowired
public DiscountPolicy setDiscountPolicy(DiscountPolicy discountPolicy) {
this.discountPolicy = discountPolicy;
}
@Primary와 @Quailifer 둘 중 어떤거 사용하지?
@Qualifier의 단점 : 모든 코드에 @Qualifier를 붙여줘야 함. 코드 길어짐. 귀찮음.
@Primary와 @Quailifer의 우선순위
@Quailifer 우선 > @Primary
스프링은 넓은 범위의 선택권 보다는 좁은 범위의 선택권이 우선순위가 높다.