본문 바로가기

소프트웨어

Spring - 중복 타입으로 자동주입

반응형

Spring 에서는 @Autowired를 통해서 혹은 유일한 생성자로 의존성 주입을 할 수 있습니다.

@Autowired는 기본적으로 타입으로 빈을 조회하는데 같은 타입의 빈이 2개 이상 컨테이너에 등록되어있을 때는 어떻게 할까요?

코드로 보자면 아래와 같은 상황입니다.

 

@Component
public class FixDiscountPolicy implements DiscountPolicy {
 
}

@Component
public class RateDiscountPolicy implements DiscountPolicy {
 
}

@Component
public class OrderServiceImpl implements OrderService {
    private final DiscountPolicy discountPolicy;
 
    public OrderServiceImpl(DiscountPolicy discountPolicy) {
        this.discountPolicy = discountPolicy;
    }
}

 

이런 상황에서는 NoUniqueBeanDefinitionException 이 터집니다..

 

nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'hello.core.discount.DiscountPolicy' available: expected single matching bean but found 2: fixDiscountPolicy,rateDiscountPolicy

 

이 상황에서는 3가지 해결방법이 있습니다.

 

1. @Autowired 필드명으로 매칭

2. @Qualifier 끼리 매칭

3. @Primary 사용

 

@Autowired 필드명으로 매칭하는건 코드를 아래와 같이 변경하면 되는데, 이것은 사용할 빈이 바뀌면 다시 수정해야 하기 때문에 유지보수 측면에서 좋지않습니다.

 

@Component
public class OrderServiceImpl implements OrderService {
    private final DiscountPolicy rateDiscountPolicy;
}

 

@Qualifier 사용도 역시 의존성을 제공하는 측과 제공받는 측 모두 수정이 일어납니다.

대체적으로 @Primary 사용이 가장 좋겠습니다.

 

아래와 같이 우선적으로 조회하고자 하는 Component에 @Primary annotation을 마킹합니다.

 

@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {

}

 

그러면, 같은 타입의 빈들이 모두 필요할 때는 어떻게 하면 될까요?

이때는 Collections로 가져올 수 있습니다

 

class DiscountService {
    private final Map<String, DiscountPolicy> discountPolicyMap;
    private final List<DiscountPolicy> discountPolicies;

    @Autowired
    public DiscountService(Map<String, DiscountPolicy> discountPolicyMap, List<DiscountPolicy> discountPolicies) {
        this.discountPolicyMap = discountPolicyMap;
        this.discountPolicies = discountPolicies;
    }
}

 

타입이 같은 상황, 지금 이 포스팅에서는 같은 인터페이스를 구현하고 그 인터페이스 타입으로 의존성 주입을 시도하는 상황입니다.

 

이런 상황에서 Bean을 특정하는 방법과 그 Bean들을 모두 가져오는 방법에 대해서 알아봤습니다!!

반응형