조회 빈이 여러개일 경우 해결 방법

초보개발·2021년 12월 16일
0

Spring

목록 보기
22/37

조회 빈이 2개 이상일 경우

@Autowired는 타입으로 조회하는데, 같은 타입의 빈이 2개 이상일 경우 문제가 발생하게 된다.
예를 들어, DiscountPolicy의 구현체인 FixDiscountPolicyRateDiscountPolicy를 스프링 빈으로 선언한다.

@Component
public class FixDiscountPolicy implements DiscountPolicy {}

@Component
public class RateDiscountPolicy implements DiscountPolicy {}

@Autowired를 이용해 의존관계를 자동 주입하면

@Autowired private DiscountPolicy discountPolicy;

NoUniqueBeanDefinitionException 오류가 발생하며 상세하게 2개의 빈이 발견되었다고 알려준다.
이 때, 하위 타입으로 지정할 수 있으나 하위 타입으로 지정하는 것은 DIP 원칙(역할에 의존하지 구체적인 것에 의존하면 안됨)을 위배하며 유연성도 떨어진다. 또한 이름만 다른데 완전히 같은 타입의 스프링 빈이 2개 있을 때에는 해결이 되지 않는다.
스프링 빈을 수동 등록해서 해결할 수 있지만, 의존 관계 자동 주입에서도 해결할 수 있는 방법이 여러 개 존재한다.

해결 방법

  • @Autowired 필드 명 매칭
  • @Qualifier -> @Quilifier끼리 매칭 -> 빈 이름 매칭
  • @Primary 매칭

1. @Autowired 필드 명 매칭

@Autowired는 타입 매칭을 시도하고 이 경우 여러 개의 빈이 있다면 필드 이름, 파라미터의 이름으로 스프링 빈 이름을 추가 매칭한다.

@Autowired private DiscountPolicy rateDiscountPolicy;

필드 명이 rateDiscountPolicy이므로 정상적으로 의존관계가 주입된다. 필드 이름 매칭은 먼저 타입 매칭을 시도하고 그 결과가 여러 빈이 존재할 경우 추가로 동작하는 기능이다.

2. @Qualifier 사용

@Qualifier는 추가 구분자를 붙여주는 방법인데, 주입할 때 추가적인 방법을 제공할 뿐 빈 이름을 변경하지 않는다.

@Component
@Qualifier("fixDiscountPolicy")
public class FixDiscountPolicy implements DiscountPolicy {}
  • 생성자 주입
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, @Qualifier("fixDiscountPolicy") DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }
  • 수정자 주입
@Autowired
public DiscountPolicy setDiscountPolicy(@Qualifier("fixDiscountPolicy") DiscountPolicy discountPolicy) {
    retrun discountPolicy;
}
  • 직접 @Bean으로 빈 등록할 때에도 사용한다.
@Bean
@Qualifier("fixDiscountPolicy")
public DiscontPolicy discountPolicy() {...}

@Qualifier로 주입할 때 @Qualifier("fixDiscountPolicy")를 찾지 못한다면, fixDiscountPolicy이라는 이름을 갖는 스프링 빈을 추가적으로 탐색한다. 그래도 없다면 NoSuchBeanDefinitionException 오류가 발생한다.
하지만 @Qualifier은 @Qualifier를 찾는 용도로만 사용하는 것이 좋다.

3. @Primary

@Primary는 우선순위를 정하는 방법인데, @Autowired할 때 여러 빈이 매칭된다면 @Primary가 우선권을 갖게 된다. DiscountPolicy의 구현체 중 RateDiscountPolicy에게 우선권을 주게되면 이 구현 클래스에 주입이 된다.

@Qualifier와 @Primary

스프링은 자세한 것이 항상 우선권을 가져가게 되므로 매우 상세하게 작동되는 @Qualifier가 @Primary보다 우선순위가 높다.

0개의 댓글