스프링을 공부하다 보면 의존성 주입(DI)을 할 때 "같은 종류의 빈(Bean)이 여러 개일 때 어떻게 하지?"라는 문제에 부딪히게 됩니다.
지난 시간에 우리는 두 가지 해결책을 배웠습니다.
그럼 실전에서는 도대체 언제 @Primary를 쓰고, 언제 @Qualifier를 써야 할까요? 오늘 그 기준을 확실하게 잡아드립니다.
이해를 돕기 위해 우리가 아주 복잡한 프로그램을 만든다고 가정해 봅시다. 데이터를 정렬해야 해서 SortingAlgorithm 인터페이스를 만들었고, 이를 구현한 3가지 정렬 방식이 있습니다.
QuickSort (퀵 정렬)BubbleSort (버블 정렬)RadixSort (기수 정렬)그리고 이 정렬 알고리즘을 사용하는 고객(Client) 클래스도 두 개가 있습니다.
ComplexAlgorithm (일반 고객)AnotherComplexAlgorithm (까다로운 고객)@Primary와 @Qualifier 중 무엇을 쓸지 결정하는 가장 중요한 기준은 "이 의존성을 사용하는 클래스의 관점"에서 생각하는 것입니다.
@Primary)ComplexAlgorithm은 정렬만 되면 되고, 딱히 까다로운 조건이 없습니다.
"사장님, 여기서 제일 잘나가는 정렬 알고리즘 하나 주세요. (알아서 주시면 됩니다.)"
이럴 때는 범용적으로 쓰이는 QuickSort에 @Primary를 붙여두면 됩니다.
@Component
@Primary // "내가 대표 선수야!"
public class QuickSort implements SortingAlgorithm { ... }
이렇게 하면 ComplexAlgorithm이 @Autowired만 써도 스프링이 알아서 대표 선수인 QuickSort를 가져다줍니다.
@Qualifier)반면, AnotherComplexAlgorithm은 아주 특이한 상황이라서 반드시 RadixSort를 써야만 합니다.
"사장님, 저는 다른 거 말고 꼭 'Radix'로 주세요. 그거 아니면 안 돼요."
이럴 때는 @Qualifier를 사용해서 특정 빈을 강제로 주입받아야 합니다.
// 1. 빈(Bean)에 이름표 붙이기
@Component
@Qualifier("RadixSortQualifier")
public class RadixSort implements SortingAlgorithm { ... }
// 2. 사용할 때 이름표 부르기
@Component
public class AnotherComplexAlgorithm {
@Autowired
@Qualifier("RadixSortQualifier") // "RadixSortQualifier 내놔!"
private SortingAlgorithm sortingAlgorithm;
}
만약 QuickSort에는 @Primary가 붙어 있고, RadixSort에는 @Qualifier가 붙어 있다면? 그리고 제가 @Qualifier로 RadixSort를 불렀다면 누가 올까요?
정답: @Qualifier가 이깁니다.
스프링은 항상 넓은 범위의 기본 설정(@Primary)보다 구체적인 상세 설정(@Qualifier)을 우선시합니다.
@Qualifier 이름 짓기 귀찮다면?@Qualifier("이름")을 일일이 적기 귀찮거나, 이름을 안 적었을 때는 어떻게 할까요?
스프링은 똑똑하게도 빈(Bean)의 이름(클래스명)을 한정자로 사용할 수 있게 해 줍니다.
RadixSortradixSort (첫 글자만 소문자)따라서 아래 코드는 작동합니다.
// 별도의 @Qualifier 어노테이션이 없더라도
@Autowired
@Qualifier("radixSort") // 빈 이름(클래스명 camelCase)을 적으면 찾아서 연결해줌!
private SortingAlgorithm sortingAlgorithm;
의존성을 주입받는 클래스 입장에서 생각하세요.
@Primary에 맡긴다 (@Autowired만 사용).@Qualifier로 콕 집어 부른다.이 원칙만 기억하면 복잡한 의존성 주입도 문제없습니다! 다음 시간에는 이 개념들을 활용한 더 재미있는 예제를 살펴보겠습니다.