Spring @Primary와 @Qualifier 어노테이션 쉽게 이해하기
Spring에서는 하나의 인터페이스를 여러 개의 구현체가 가질 수 있습니다.
이때, 특정 구현체를 선택해서 사용할 수 있도록 도와주는 것이 @Primary와 @Qualifier 어노테이션입니다.
이번 글에서는 두 어노테이션의 차이와 사용법을 쉽게 설명하겠습니다.
1. @Primary 어노테이션
@Primary는 동일한 타입의 빈이 여러 개 존재할 때, 우선적으로 선택할 빈을 지정하는 어노테이션입니다.
✅ 예제 코드
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
interface Printer {
void print();
}
@Component
@Primary // 기본적으로 선택될 빈 지정
class LaserPrinter implements Printer {
@Override
public void print() {
System.out.println("레이저 프린터 출력");
}
}
@Component
class InkjetPrinter implements Printer {
@Override
public void print() {
System.out.println("잉크젯 프린터 출력");
}
}
✅ @Primary 적용 시 동작
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
class PrintService {
private final Printer printer;
@Autowired
public PrintService(Printer printer) {
this.printer = printer;
}
public void doPrint() {
printer.print();
}
}
위 코드에서 PrintService는 Printer 타입의 빈을 자동 주입받습니다. LaserPrinter가 @Primary로 지정되었으므로 자동으로 선택됩니다.
✅ 실행 결과
레이저 프린터 출력
2. @Qualifier 어노테이션
@Qualifier는 특정한 빈을 명시적으로 선택할 때 사용합니다. @Primary가 설정되어 있어도 @Qualifier를 사용하면 지정된 빈이 우선됩니다.
✅ @Qualifier 적용 예제
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
class QualifierPrintService {
private final Printer printer;
@Autowired
public QualifierPrintService(@Qualifier("inkjetPrinter") Printer printer) {
this.printer = printer;
}
public void doPrint() {
printer.print();
}
}
✅ 실행 결과
잉크젯 프린터 출력
3. @Primary vs @Qualifier 차이점
| 어노테이션 | 동작 방식 |
| @Primary | 기본적으로 선택될 빈을 지정할 때 사용 |
| @Qualifier | 특정한 빈을 명시적으로 지정할 때 사용 |
- @Primary는 우선 순위를 부여하는 방식, @Qualifier는 명확하게 지정하는 방식입니다.
- @Qualifier가 사용되면 @Primary는 무시됩니다.
4. @Primary와 @Qualifier 함께 사용하기
@Primary는 기본 선택 빈을 정할 때 유용하지만, 특정 상황에서 다른 빈을 선택하고 싶을 수도 있습니다. 그럴 때 @Qualifier를 함께 사용하면 더욱 유연한 설정이 가능합니다.
✅ 예제 코드
@Component
@Primary
class DefaultPrinter implements Printer {
@Override
public void print() {
System.out.println("기본 프린터 출력");
}
}
@Component("fastPrinter")
class FastPrinter implements Printer {
@Override
public void print() {
System.out.println("빠른 프린터 출력");
}
}
@Component
class MixedPrintService {
private final Printer printer;
@Autowired
public MixedPrintService(@Qualifier("fastPrinter") Printer printer) {
this.printer = printer;
}
public void doPrint() {
printer.print();
}
}
✅ 실행 결과
빠른 프린터 출력
@Primary가 설정된 DefaultPrinter가 있음에도 불구하고, @Qualifier("fastPrinter")를 사용했기 때문에 FastPrinter가 주입되었습니다.
5. 정리
🎯 언제 @Primary를 사용해야 할까?
- 특정 타입의 빈이 여러 개 있을 때 기본적으로 사용할 빈을 설정할 때.
- 같은 인터페이스의 여러 구현체 중 가장 많이 사용하는 빈을 지정할 때.
🎯 언제 @Qualifier를 사용해야 할까?
- 특정한 구현체를 명확하게 지정해야 할 때.
- @Primary가 설정된 빈이 있지만 다른 빈을 선택해야 할 때.
- 동일한 인터페이스의 여러 개의 구현체를 상황에 따라 다르게 주입해야 할 때.
6. 마무리
@Primary와 @Qualifier는 Spring에서 의존성 주입 시 특정 빈을 선택하는 방법입니다. 기본적으로 @Primary를 활용하고, 특정한 빈을 선택해야 할 경우 @Qualifier를 사용하면 됩니다. 상황에 맞게 두 어노테이션을 적절히 조합하여 사용하면, 더욱 유연한 Spring 애플리케이션을 만들 수 있습니다. 😊