스프링 핵심 원리 - 기본편 - 인프런 | 강의
스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., - 강의 소개 | 인프런...
www.inflearn.com
본 포스팅은 <스프링 핵심 원리 - 기본편> 강의 내용을 복습하기 위해 간략히 작성된 글이므로 전체 내용은 위 강의에서 확인 가능합니다.
2. 객체지향의 5가지 원칙(SOLID), 관심사의 분리
7. @Autowired 필드명 매칭, @Qualifier, @Primary
들어가기 전에
컴포넌트 스캔에 대해 배울 때 동작 과정을 공부하면서 이런 이야기를 했었습니다. 한 인터페이스를 구현하는 객체가 A, B 두 개라고 했을 때 내가 주입하고 싶은 객체에 @Component 애노테이션을 붙여 컴포넌트 스캔이 스프링 빈으로 등록할 수 있게 해주고 @Autowired로 해당 구현 객체를 찾아 생성자에 주입하면 된다고요.
만약 이 A와 B를 모두 스프링 빈으로 선언하고 의존관계 자동 주입을 실행하면 어떻게 될까요? 예제를 같이 보겠습니다.
@Component
public class FixDiscountPolicy implements DiscountPolicy()
@Component
public class RateDiscountPolicy implements DiscountPolicy {}
@Autowired
private DiscountPolicy discountPolicy
@Autowired는 타입으로 조회를 하기 때문에 오류가 발생하게 되는데요. 오류 메세지는 다음과 같습니다.
NoUniqueBeanDefinitionException: No qualifying bean of type
'hello.core.discount.DiscountPolicy' available: expected single matching bean
but found 2: fixDiscountPolicy,rateDiscountPolicy
하나의 빈을 기대했는데, 두 개가 발견되었다고 말이죠. 이럴 때는 어떻게 해결할 수 있을까요?
조회 빈이 2개 이상일 때 해결 방법
해결 방법은 세 가지 입니다.
- @Autowired 필드 명 매칭
- @Qualifier → @Qualifier끼리 매칭 → 빈 이름 매칭
- @Primary 사용
1. @Autowired 필드 명 매칭
@Autowired는 타입 매칭을 시도하고, 이때 여러 개의 빈이 있으면 필드 이름, 파라미터 이름으로 빈 이름을 추가로 매칭합니다.
기존 코드
@Autowired
private DiscountPolicy discountPolicy
필드 명을 빈 이름으로 변경
@Autowired
private DiscountPolicy rateDiscountPolicy
2. @Qualifier
주입할 때 추가 구분자를 붙여주는 방법입니다.
@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
@Qualifier("fixDiscountPolicy")
public class FixDiscountPolicy implements DiscountPolicy {}
@Autowired
public OrderServiceImpl(MemberRepository memberRepository,
@Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
만약 @Qualifier로 주입할 때 @Qualifier("mainDiscountPolicy")를 찾지 못하면 어떻게 될까요? 그 때는 mainDiscountPolicy라는 이름의 스프링 빈을 추가로 찾습니다. 하지만 최대한 @Qualifier 용도에 초점을 맞출 수 있게 잘 사용하는 게 좋아요!
하지만 @Qualifier("mainDiscountPolicy")처럼 문자로 적게 되면 컴파일시에 타입 체크가 안되는데요. 그러면 애노테이션을 만들어서 해결할 수 있습니다.
애노테이션 만들기
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER,
ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier("mainDiscountPolicy")
public @interface MainDiscountPolicy {
}
@Component
@MainDiscountPolicy
public class RateDiscountPolicy implements DiscountPolicy {}
//생성자 자동 주입
@Autowired
public OrderServiceImpl(MemberRepository memberRepository,
@MainDiscountPolicy DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
3. @Primary 사용
우선순위를 정하는 방법으로 여러 빈이 매칭되면 이 애노테이션을 사용한 빈이 우선권을 갖게 됩니다.
@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;
}
참고로 Primary보다 Qualifier가 더 상세하게 동작되기 때문에 우선권이 높습니다.
'Spring' 카테고리의 다른 글
[Spring] 빈 스코프 (0) | 2022.09.17 |
---|---|
[Spring] 빈 생명주기 콜백 (1) | 2022.09.17 |
[Spring] 컴포넌트 스캔 (0) | 2022.09.17 |
[Spring] 싱글톤 패턴과 싱글톤 컨테이너 (0) | 2022.09.17 |
[Spring] 스프링 컨테이너와 스프링 빈 (0) | 2022.09.14 |