본문 바로가기
Spring

[Spring] @Autowired 필드명 매칭, @Qualifier, @Primary

by soro.k 2022. 9. 17.

 

스프링 핵심 원리 - 기본편 - 인프런 | 강의

스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., - 강의 소개 | 인프런...

www.inflearn.com

본 포스팅은 <스프링 핵심 원리 - 기본편> 강의 내용을 복습하기 위해 간략히 작성된 글이므로 전체 내용은 위 강의에서 확인 가능합니다. 

 

1. 스프링이란

2. 객체지향의 5가지 원칙(SOLID), 관심사의 분리 

3. 제어의 역전(IoC)과 의존관계 주입(DI)

4. 스프링 컨테이너와 스프링 빈

5. 싱글톤 패턴과 싱글톤 컨테이너

6. 컴포넌트 스캔

7. @Autowired 필드명 매칭, @Qualifier, @Primary

8. 빈 생명주기 콜백

9. 빈 스코프


들어가기 전에

컴포넌트 스캔에 대해 배울 때 동작 과정을 공부하면서 이런 이야기를 했었습니다. 한 인터페이스를 구현하는 객체가 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