해당 예시에서는 @RequiredArgsConstructor를 사용하지 않는다.

@RequiredArgsConstructor + @Qualifier를 사용할 경우 따로 설정을 잡아줘야 한다.

아래 포스팅 참조

 

조회 대상 빈이 2개 이상인 경우 NoUniqueBeanDefinitionException 오류가 발생한다.

 

예시) 

public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
	this.memberRepository = memberRepository;
	this.discountPolicy = discountPolicy;
}

생성자 주입 시 인터페이스(역할)를 통해 주입을 받는데 DiscountPolicy를 implements 한 클래스가 2개 이상이다. 이 경우 스프링 컨테이너는 어떤 클래스(구현 객체)를 주입해야 할지 몰라 에러를 발생시킨다

 

역할 - 뮤지컬의 배역

구현 객체 - 배역을 맞은 사람

 

조회 대상 빈이 2개 이상일 때 해결 방법

  • @Autowired 필드 명 매칭
  • @Qualifier @Qualifier끼리 매칭 빈 이름 매칭
  • @Primary 사용

 

@Primary, @Qualifier 활용

코드에서 자주 사용하는 메인 데이터베이스의 커넥션을 획득하는 스프링 빈이 있고, 코드에서 특별한 기능으로 가끔 사용하는 서브 데이터베이스의 커넥션을 획득하는 스프링 빈이 있다고 생각해보자. 

메인 데이터베이스의 커넥션을 획득하는 스프링 빈은 @Primary를 적용해서 조회하는 곳에서 @Qualifier 지정 없이 편리하게 조회하고, 서브 데이터베이스 커넥션 빈을 획득할 때는 @Qualifier를 지정해서 명시적으로 획득 하는 방식으로 사용하면 코드를 깔끔하게 유지할 수 있다. 

 

물론 이때 메인 데이터베이스의 스프링 빈을 등록할 때 @Qualifier를 지정해주는 것은 상관없다.

 

우선순위

@Primary 는 기본값처럼 동작하는 것이고, @Qualifier는 매우 상세하게 동작한다. 이런 경우 어떤 것이 우선권을 가져갈까? 

스프링은 자동보다는 수동이, 넒은 범위의 선택권보다는 좁은 범위의 선택권이 우선순위가 높다. 

따라서 여기서도 @Qualifier 가 우선권이 높다.

 

 

1. @Autowired 필드 명 매칭


@Autowired는 타입 매칭을 시도하고, 이때 여러 빈이 있으면 필드 이름, 파라미터 이름으로 빈 이름을 추가 매칭 한다.
기존 코드

@Autowired
private DiscountPolicy discountPolicy

필드 명을 빈 이름으로 변경

@Autowired
private DiscountPolicy rateDiscountPolicy

필드 명이 rateDiscountPolicy 이므로 정상 주입된다.

필드 명 매칭은 먼저 타입 매칭을 시도하고 그 결과에 여러 빈이 있을 때 추가로 동작하는 기능이다.

 

@Autowired 매칭 정리
1. 타입 매칭
2. 타입 매칭의 결과가 2개 이상일 때 필드 명, 파라미터 명으로 빈 이름 매칭

 

-> 필드명 주입은 필드명 변경에 따른 코드 수정이 뒤따라 오므로 사용하지 않는것이 좋을 것 같다.

 

 

2. @Qualifier 사용

@Qualifier는 추가 구분자를 붙여주는 방법이다. 주입 시 추가적인 방법을 제공하는 것이지 빈 이름을
변경하는 것은 아니다.

-> 빈 등록 시 @Qualifier를 붙여 준다.

@Component
@Qualifier("fixDiscountPolicy")
public class FixDiscountPolicy implements DiscountPolicy {}

 

-> 주입 시에 @Qualifier를 붙여주고 등록한 이름을 적어준다.

@Autowired
public OrderServiceImpl(MemberRepository memberRepository,
			@Qualifier("fixDiscountPolicy") DiscountPolicy discountPolicy) {
	this.memberRepository = memberRepository;
	this.discountPolicy = discountPolicy;
}

 

@Qualifier로 주입할 때 @Qualifier("fixDiscountPolicy")를 못 찾으면 어떻게 될까?

그러면 fixDiscountPolicy라는 이름의 스프링 빈을 추가로 찾는다.

하지만 경험상 @Qualifier는 @Qualifier를 찾는 용도로만 사용하는 게 명확하고 좋다.

 

@Qualifier 정리

1. @Qualifier끼리 매칭

2. 빈 이름 매칭

3. NoSuchBeanDefinitionException 예외 발생

 

 

3. @Primary 사용

@Primary는 우선순위를 정하는 방법이다. @Autowired 시에 여러 빈이 매칭 되면 @Primary 가 우선권을 가진다.

 

rateDiscountPolicy 가 우선권을 가지도록 하자.

# RateDiscountPolicy 클래스
@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {}


# FixDiscountPolicy 클래스
@Component
public class FixDiscountPolicy implements DiscountPolicy {}

 

@Qualifier 사용 시보다 생성자 주입 코드가 깔끔해지므로 주로 사용된다.

+ Recent posts