Spring/Framwork

조회 대상 Bean 이 2개 이상 일때 해결 방법 (+우선 순위)

밍구밍구밍 2024. 5. 3. 15:13

 

현재 DiscountPolicy 인터페이스로부터 FixDiscountPolicy 와 RateDiscountPolicy 2개의 기능의 빈을 사용하고 있다면 

컴파일 에러가 발생 한다.

@Component
public class FixDiscountPolicy implements DiscountPolicy{
@Component
public class RateDiscountPolicy implements DiscountPolicy{

 

@Component
public class OrderServiceImpl implements OrderService{

    //       기본 기능(인터페이스를 참조하는)           (실제 구현 기능의 객체 생성) 인터페이스에서 받은 것
     private final MemberRepository memberRepository;
     private final DiscountPolicy discountPolicy;


     // 생성자를 직접 생성 (객체 추가시 추가로 해당 객체를 생성자에 작성 해야된다)
    @Autowired
    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;

    }

현재 DiscountPolicy 객체를 @Autowired 를 통해 스프링빈에 등록하려고 하지만 DiscountPolicy 는 Fix 와 Rate 두개의 기능을 가지고 있기 때문에 빈의 우선순위를 결정하지 못해 컴파일 에러가 발생 한다.

 

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'orderServiceImpl' defined in file [C:\Users\rainb\OneDrive\바탕 화면\study\core\out\production\classes\hello\core\order\OrderServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 1: No qualifying bean of type 'hello.core.discount.DiscountPolicy' available: expected single matching bean but found 2: fixDiscountPolicy,rateDiscountPolicy

(요약 하자면 DiscountPolicy 라는 객체에 스프링 빈 parameter 는 1개만 담을수 있지만 현재 2개가 있다는 뜻)

 

해결 방안

1. @Autowired 필드명을 매칭

- 필드명을 변경하여 @Autowired 시킨다.

(필드명 매칭 후 코드)

@Component
public class OrderServiceImpl implements OrderService{

    //       기본 기능(인터페이스를 참조하는)           (실제 구현 기능의 객체 생성) 인터페이스에서 받은 것
     private final MemberRepository memberRepository;
     private final DiscountPolicy discountPolicy;


     // 생성자를 직접 생성 (객체 추가시 추가로 해당 객체를 생성자에 작성 해야된다)
    @Autowired
    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy rateDiscountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = rateDiscountPolicy;

    }

(DiscountPolicy → rateDiscountPolicy 로 변경)

- @Autowired 타입 매칭을 시도하고, 이 때 여러 빈이 있으면 필드 이름, 파라미터 이름으로 빈 이름을 추가 매칭한다.

- 필드명이 rateDiscountPolicy 이므로 정상 주입 된다.

 

2. @Qualifier 사용

 

- RateDiscountPolicy 를 @Qualifier 사용하여 "mainDiscountPolicy" 라는 이름으로 지정 한다.

@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy{

 

- 다음으로 RateDiscountPolicy 객체가 생성된 생성자 앞에 @Qualifier("mainDiscountPolicy")를 찾도록 지정해 준다.

@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;

    }

 

※ Qualifier 정리 (검색 순서)

step 1. @Qualifier 끼리 매칭

step 2. 빈 이름 매칭

step 3. 위 두가지 이름으로 매칭시에도 없을 시 NoSuchBeanDefinitionException 예외 발생

 

3. @Primary 사용 (우선순위 지정 방법)

@Primary 선언 시 최상위 우선 순위를 가진다.

@Component
@Primary
public class FixDiscountPolicy implements DiscountPolicy{

(*가장 보편적으로 사용)

 

※ 우선 순위 : @Primary (기본)     @Qualifier (상세)