코드 그라데이션
조회 빈이 2개 이상 - 해결 본문
해결 방법은 크게 3가지.
1. @Autowired 필드명 매칭
2. @Qualifier => @Qualifier끼리 매칭 => 빈 이름 매칭
3. @Primary 사용
@Autowired 필드명 매칭
이 생성자를 바꿔준다. 구체적 이름으로
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy rateDiscountPolicy) { // 여기 변경
this.memberRepository = memberRepository;
this.discountPolicy = rateDiscountPolicy; // 여기 변경
}
전체 코드 OrderServiceImpl
package inflearn.spring_core.order;
import inflearn.spring_core.discount.DiscountPolicy;
import inflearn.spring_core.member.Member;
import inflearn.spring_core.member.MemberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy rateDiscountPolicy) { // 여기 변경
this.memberRepository = memberRepository;
this.discountPolicy = rateDiscountPolicy; // 여기 변경
}
//테스트 용도 추가
public MemberRepository getMemberRepository() {
return memberRepository;
}
@Override
public Order createOrder(Long memberId, String itemName, int itemPrice) {
Member member = memberRepository.findById(memberId);
int discountPrice = discountPolicy.discount(member, itemPrice);
return new Order(memberId, itemName, itemPrice, discountPrice);
}
}
이렇게 하고 전 포스팅에서 실패했던 basicScan() 테스트를 다시 돌려보면
성공이 나온다.
물론 전체테스트 돌리면, xmlAppContext() 메서드는 실패가 나온다.
xml 등록할 때 discountPolicy 이름으로 등록해놨기 때문.
물론 그냥 필드명을
@Autowired
private DiscountPolicy rateDiscountPolicy;
이렇게 수정해줘도 된다. (파라미터 인젝션 말고)
필드명 매칭은 먼저 타입 매칭을 시도 하고 그 결과에 여러 빈이 있을 때 추가로 동작하는 기능이다.
@Autowired 매칭 정리
@Qualifier 사용
@Qualifier 는 추가 구분자를 붙여주는 방법이다.
주입 시 추가적인 방법을 제공하는 것이지 빈 이름을 변경하는 것은 아니다.
빈 등록시 @Qualifier를 붙여 준다.
@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
@Qualifier("fixDiscountPolicy")
public class FixDiscountPolicy implements DiscountPolicy {}
주입시에 @Qualifier를 붙여주고 등록한 이름을 적어준다.
생성자 자동 주입 예시
@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 정리
@Primary 사용
@Primary 는 우선순위를 정하는 방법이다. @Autowired 시에 여러 빈이 매칭되면 @Primary 가 우선권을 가진다.
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 와 @Qualifier 중에 어떤 것을 사용하면 좋을지 고민이 될 것이다.
@Qualifier 의 단점은 주입 받을 때 다음과 같이 모든 코드에 @Qualifier 를 붙여주어야 한다는 점이다.
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, @Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
- 반면에 @Primary 를 사용하면 이렇게 @Qualifier 를 붙일 필요가 없다.
@Primary, @Qualifier 활용
우선순위
728x90
'Spring > 핵심 원리 구현' 카테고리의 다른 글
조회한 빈이 모두 필요할 때 (0) | 2024.02.08 |
---|---|
애노테이션 직접 만들기 (0) | 2024.02.07 |
조회 빈이 2개 이상 - 문제 (0) | 2024.02.06 |
Lombok과 최신 트렌드 (0) | 2024.02.06 |
생성자 주입을 선택하라 (1) | 2024.02.05 |
Comments