@Autowired 자동 주입은 객체의 '타입'으로 조회한 빈을 주입한다.
@Autowired
private DiscountPolicy discountPolicy
.
.
@Component
public class FixDiscountPolicy implements DiscountPolicy {
}
.
.
@Component
public class RateDiscountPolicy implements DiscountPolicy {
}
바람직한 설계는 인터페이스에 의존하는 것이다.
위와 같은 코드에서 discountPolicy에 주입할 빈들을 조회하면 해당 인터페이스를 구현한 모든 구현체들의 빈이 조회될 것이다.
그럼 그 여러 가지 빈들 중 어느것을 주입해야할까?
세 가지 방법이 존재한다.
1. 필드명 매칭
조회된 빈들 중에서 자동주입이 되어야 하는 필드 변수의 이름과 같은 이름의 빈이 있다면 이 빈을 우선적으로 등록한다.
@Component
public class OrderServiceImpl implements OrderService{
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
@Autowired // 파라미터 변수명 rateDiscountPolicy
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy rateDiscountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = rateDiscountPolicy;
}
}
타입은 DiscountPolicy 이지만 생성자의 파라미터 이름은 rateDiscountPolicy 이다.
조회된 빈들(fixDiscountPolicy, rateDiscountPolicy) 중 필드명과 이름이 같은 빈인 rateDiscountPolicy 가 우선적으로 주입되게 된다.
(생성자 주입이 아닌 필드 주입을 사용하는 경우에도 동일하게 적용된다.)
2. @Qualifier
public class BlahBlah {
private final DiscountPolicy discountPolicy
@Autowired
public BlahBlah(@Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {
this.discountPolicy = discountPolicy;
}
}
.
.
@Component
@Qualifier("fixDiscountPolicy")
public class FixDiscountPolicy implements DiscountPolicy {
}
.
.
@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy {
}
@Qualifier는 의존성 주입에 있어 추가적인 구분 방법일 뿐 빈 이름을 변경하는 것은 아니라는 것에 주의하자
(@Qualifier 역시 필드 주입에서도 사용 가능하다)
만약 @Qualifier("mainDiscountPolicy") 가 일치하는 빈을 찾지 못한다면 차선책으로 빈 이름이 mainDiscountPolicy인 빈을 찾는다.
(이 기능은 굳이 사용되게 하지 않도록 하는 것이 좋다)
@Qualifier 는 ComponentScan 이 아닌 @Bean 직접 등록할 때에도 달아넣을 수 있다.
(추가)
Lombok의 @RequiredArgsConstructor 을 사용해서 생성자를 만들 경우 @Qualifier를 사용하지 못한다.
@RequiredArgsConstructor 는 어노테이션까지 포함해 생성자를 만들 수 없다.
www.inflearn.com/questions/71872
위 링크에 @RequiredArgsConstructor과 @Qualifier를 같이 사용할 수 있는 방법이 나와있지만 귀찮으니 그냥 같이 쓰지는 말자
3. @Primary (자주 사용함, 편하지만 한계점이 있다)
그냥 우선순위를 주고 싶은 빈의 클래스에 @Primary 를 달아주면 된다.
@Autowired
private DiscountPolicy discountPolicy
.
.
@Component
public class FixDiscountPolicy implements DiscountPolicy {
}
.
.
@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {
}
만약 @Primary와 @Qualifier가 겹치는 상황이 발생한다면?
-> @Qualifier가 우선된다.
스프링은 항상 포괄적인 개념보다는 상세한 개념을 우선시 한다.
(수동등록 > 자동등록 처럼)
'김영한님 스프링 강의 정리 > 핵심원리 기본편' 카테고리의 다른 글
빈 스코프 @Scope, ObjectProvider<T> (0) | 2021.01.16 |
---|---|
빈 생명주기 콜백 (0) | 2021.01.15 |
Lombok 라이브러리를 사용한 생성자 주입 (0) | 2021.01.11 |
의존성 주입 @Autowired, 옵션 처리 설정 (0) | 2021.01.11 |
빈 이름 중복에 의한 충돌 (0) | 2021.01.10 |