@Qualifier, @Primary

2022. 4. 12. 12:44
반응형

스프링에서 의존관계 자동주입을 하는데, 자동주입 할 대상이 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

BELATED ARTICLES

more