@Qualifier, @Primary
스프링에서 의존관계 자동주입을 하는데, 자동주입 할 대상이 2개 이상이 존재하면 어떻게 구분을할까? 스프링은 사용자가 @Autowired를 붙여주는 의존관계 자동주입 이외의 일을 하지 않는다면, 자동주입 할 대상이 2개 이상이면 NoUniqueBeanDefinitionException 예외를 터뜨린다. 따라서 의존관계 주입할 대상이 2개 이상이면 사용자가 어떤 대상에게 우선권을 줄것인지, 아니면 어떤 비즈니스 로직에 어떤 주입을 할 것인지에 대한 처리를 해야한다.
만약 여기서 자동주입이 잘 안된다는 이유로 인터페이스가 아닌 구현체로 자동주입을 명시하면 DIP를 위반하고 유연성이 떨어지기 때문에 그런일은 하지 않길 바란다.
본격적으로 해결방법을 알아보자. 조회 대상 빈이 2개 이상일 때 해결 방법은 다음과같이 3가지가 존재한다.
- @Autowired 필드 명 매칭
- @Qualifier -> @Qualifier 끼리 매칭 빈 이름 매칭
- @Primary 사용
@Autowired 필드 명 매칭
스프링은 타입이 같더라도 필드 명이 다르면 필드 명에 따라서 의존관계 주입을 시도한다. 하는 방법은 다음과 같이 간단하다.
@Autowired
private DiscountPolicy discountPolicy
위의 코드를 아래의 코드로 변경하면 된다.
@Autowired
private DiscountPolicy rateDiscountPolicy
이렇게 변경하면 스프링이 자동으로 RateDiscountPolicy라는 클래스가 있는지 찾고 해당 타입을 주입해준다.
@Qualifier
@Qualifier는 추가 구분자를 넣어서 구분해주는 것이다. 빈 이름을 변경하는 것이 아니고 구분할 수 있는 별명을 넣어주는 것이다. 사용 방법은 다음과같이 주입할 구현체들의 클래스 필드에 @Qualifier를 붙이고, 의존관계 주입시에 @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를 명시해줘야 동작한다는 점이 마음에 안든다. 다음 방법을 한번 써보자.
@Primary
@Primary는 단순히 어떤 구현체에 우선순위를 정해서 걸어두는 방법이다. 의존관계 자동주입시에 여러 빈이 매칭되면 @Primary가 우선권을 가지고 동작한다.
@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
public class FixDiscountPolicy implements DiscountPolicy {}
@Primary를 사용하면 의존관계를 주입하는 곳에서는 @Primary를 붙일 필요가 없다.
그렇다면 @Primary와 @Qualifier는 각각 어느 상황에서 사용하면 좋을까? 메인 데이터베이스의 커넥션을 자주 획득하는 스프링 빈이 있고, 가끔 사용하는 서브 데이터베이스의 커넥션을 획득하는 스프링 빈이 있다고 가정하자. 메인 데이터베이스의 커넥션을 획득하는 스프링 빈은 @Primary를 적용하여 @Qualifier지정 없이 편하게 조회하고, 서브 데이터베이스 커넥션 빈을 획득할 때는 @Qualifier를 지정해서 명시적으로 획득하는 방식으로 사용하면 코드를 깔끔하게 유지할 수 있다.
'Spring Framework > Spring 기본원리' 카테고리의 다른 글
IoC, DI, 컨테이너 (0) | 2021.02.02 |
---|---|
좋은 객체지향설계의 5가지 원칙 (0) | 2021.01.21 |