@Autowired는 주입할 빈을 타입으로 찾는다.
예를 들어 코드가 다음과 같을 때, 스프링 컨테이너는 DiscountPolicy 타입의 빈을 찾아 주입하는 방식이다.
@Autowired
private DiscountPolicy discountPolicy
등록된 빈 중에서 타입이 DiscountPolicy인 빈이 하나밖에 없다면 문제되지 않겠지만,
아래처럼 같은 타입의 빈이 여러개 등록되어 있다면 오류 (NoUniqueBeanDefinitionException)가 발생한다.
@Component
public class FixDiscountPolicy implements DiscountPolicy {}
@Component
public class RateDiscountPolicy implements DiscountPolicy {}
이러한 중복을 해결하는 방법이 몇 가지 있다.
- @Autowired에 필드명 지정
- @Qualifier("alterName")
- @Primary
@Autowired에 필드명 매칭
@Autowired는
1. 처음에 타입으로 매칭하고,
2. 중복되는 빈이 있을 경우 필드 이름, 파라미터 이름으로 빈 이름을 다시 매칭한다.
즉 필드명을 다음과 같이 바꾸면 빈 중복 문제를 해결할 수 있다.
@Component
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy rateDiscountPolicy; // 필드 이름을 rateDiscountPolicy로 변경
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.rateDiscountPolicy = discountPolicy;
}
}
@Qualifier("alterName")
@Qualifier는 추가적인 구분자를 지정해주는 방식이다.
클래스 선언부에 @Qualifier("alterName")을 붙여주면, 해당 클래스는 기본적으로 지정되는 빈 이름에 추가적으로 alterName이라는 이름으로 조회할 수 있다.
방법
1. 빈으로 등록할 클래스 선언부에 @Qualifier를 붙인다.
@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy {
...
}
다른 빈에도 붙여줄지는 임의로 판단
@Component
@Qualifier("fixDiscountPolicy")
public class FixDiscountPolicy implements DiscountPolicy {
...
}
2. 해당 빈을 주입받는 코드에 @Qualifier로 등록한 구분자를 지정한다.
생성자 자동 주입 예시 (파라미터에 지정, 수정자도 동일)
@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;
}
}
빈 수동 등록 예시
@Bean
@Qualifier("mainDiscountPolicy")
public DiscountPolicy discountPolicy() {
return new ...
}
특징
- @Qualifier로 추가한 구분자와 빈 이름은 혼용해서 사용 가능하다.
- 다만, @Qualifier로 추가한 구분자는 추가한 구분자끼리만 구분하는 용도로 쓰는 것이 바람직하다.
상식적으로 생각해봐도 혼용하면 헷갈린다.
- 다만, @Qualifier로 추가한 구분자는 추가한 구분자끼리만 구분하는 용도로 쓰는 것이 바람직하다.
- 구분자 지정에 단순 문자열을 사용하기 때문에, 오타 등을 잡아주지 못한다.
- 필요할 때마다 @Qualifier를 붙여주어야 한다. (해당 빈을 주입받는 모든 코드에 @Qualifier를 붙여주어야 한다.)
@Primary
@Primary는 빈에 우선 순위를 부여하는 방식이다.
같은 타입의 빈이 여러개 매칭될 경우 @Primary로 지정된 빈이 우선권을 가진다.
예를 들어 RateDiscountPolicy가 우선적으로 매칭되도록 하고 싶다면, 해당 클래스에 @Primary를 붙여주면 된다.
@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {
...
}
@Component
public class FixDiscountPolicy implements DiscountPolicy {
...
}
권장 사용 방식
주로 사용하는 빈을 @Primary로 등록하고, 특별한 경우에 사용할 빈을 @Qualifier로 지정해서 사용하도록 설정하면 깔끔하게 코드를 작성할 수 있다.
즉 @Priamry와 @Qualifier를 함께 사용하는 것이 권장된다.
@Primary와 @Qualifier 사이의 우선 순위
스프링은 넓은 범위보다는 자세한 범위에 대한 우선순위가 더 높다.
즉 @Primary로 등록한 빈이 있더라도, 주입할 빈을 @Qualifier로 명시한 경우 @Qualifier로 지정한 빈으로 적용된다.
'[inflearn] 스프링 핵심 원리 - 기본편 > 섹션 7 - 의존관계 자동 주입' 카테고리의 다른 글
7-6. 해당 타입의 빈이 모두 필요한 경우 (0) | 2024.05.26 |
---|---|
7-5-1. 어노테이션을 만들어 지정 (0) | 2024.05.26 |
7-4. 롬복 라이브러리 (0) | 2024.05.26 |
7-3. 생성자 주입을 권장하는 이유 (0) | 2024.05.26 |
7-2. 의존관계 주입 옵션 처리 (0) | 2024.05.26 |