본문 바로가기
Spring

[Spring] @Qualifier, @Primary

by 감자b 2024. 12. 27.

@Autowired로 의존 관계를 자동 주입할 때 해당 애노테이션은 타입으로 빈 조회 후 주입한다.

이 때 조회 대상의 빈이 2개 이상이면 자동 주입 시 문제가 발생할 수 있다.

이 문제를 해결하기 위한 방법은 크게 3가지로 나눌 수 있다.

 

예를 들어 다음과 같은 서비스가 있다고 하자.

public interface PaymentService {
    void pay();
}

@Service
public class NaverPayService implements PaymentService {
    @Override
    public void pay() {
        System.out.println("네이버 페이 결제");
    }
}

@Service
public class KakaoPayService implements PaymentService {
    @Override
    public void pay() {
        System.out.println("카카오 페이 결제");
    }
}

이 경우 컴포넌트 스캔에 의해 2개의 PaymentService가 빈으로 등록될 것이다.

 

그리고 컨트롤러에서 해당 서비스를 다음과 같이 사용 중이다.

그렇다면 자동 주입을 받는 부분에서 스프링 컨테이너는 어떤 PaymentService를 주입해야할 지 몰라서 오류가 발생할 것이다.

@RestController
public class PaymentController {

    private final PaymentService paymentService;

    @Autowired
    public PaymentController(PaymentService paymentService) {
        this.paymentService = paymentService;
    }

    @GetMapping("/pay")
    public String pay() {
        paymentService.pay();
        return "Payment processed!";
    }
}

 

1. @Qualifier

  • 위 애노테이션을 사용해 추가 구분자를 붙여주는 방법으로 실제 빈 이름을 변경하는 것은 아니다.
@Service
@Qualifier("mainPayService")
public class NaverPayService implements PaymentService {
    @Override
    public void pay() {
        System.out.println("네이버 페이 결제");
    }
}
@Autowired
public PaymentController(@Qualifier("mainPayService") PaymentService paymentService) {
    this.paymentService = paymentService;
}

이 때 Qualifier로 명시한 구분자를 찾지 못한다면 해당 구분자의 빈 이름을 조회함.

→ 명확하지 않으므로 구분자로 구분할 때만 사용하는 것이 좋음

→ 해당 구분자의 빈 이름을 가지고 있는 빈이 없다면 NoSuchBeanDefinitionException 예외 발생

위 상황에서 구분자를 직접 문자로 적는데 이럴 때 문자를 잘못 적는 실수를 하면 컴파일 상황에서 에러를 찾을 수 없다.

따라서 애노테이션을 만들어서 이 문제를 해결할 수 있다.

 @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER,
 ElementType.TYPE, ElementType.ANNOTATION_TYPE})
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
 @Qualifier("mainPayService")
 public @interface MainPayService {
 }
@Autowired
public PaymentController(@MainPayService PaymentService paymentService) {
    this.paymentService = paymentService;
}

참고로 애노테이션은 상속 기능이 없는데 이게 가능한 이유는 스프링이 지원하는 기능임.

 

2. @Primary

  • 우선 순위를 정하는 방법으로 여러 빈이 조회 시 해당 애노테이션이 우선 순위를 가짐
@Service
@Primary // 우선 순위
public class NaverPayService implements PaymentService {
    @Override
    public void pay() {
        System.out.println("네이버 페이 결제");
    }
}

@Service
public class KakaoPayService implements PaymentService {
    @Override
    public void pay() {
        System.out.println("카카오 페이 결제");
    }
}

 

만약 @Qualifier와 @Primary를 동시에 사용하고 있다면? 더 상세하게 동작하는 @Qualifier가 우선 순위.

'Spring' 카테고리의 다른 글

[Spring] 메시지, 국제화  (0) 2024.12.27
[Spring] Spring MVC  (0) 2024.12.27
[Spring] 서블릿과 컨트롤러  (0) 2024.12.27
[Spring] 스프링 컨테이너, 빈  (0) 2024.12.27
[Spring] 스프링의 이해, 스프링 부트  (0) 2024.12.27