@Autowired 자동 주입은 객체의 '타입'으로 조회한 빈을 주입한다.

@Autowired
private DiscountPolicy discountPolicy
.
.
@Component
public class FixDiscountPolicy implements DiscountPolicy {
}
.
.
@Component
public class RateDiscountPolicy implements DiscountPolicy {
}

바람직한 설계는 인터페이스에 의존하는 것이다.

위와 같은 코드에서 discountPolicy에 주입할 빈들을 조회하면 해당 인터페이스를 구현한 모든 구현체들의 빈이 조회될 것이다.

그럼 그 여러 가지 빈들 중 어느것을 주입해야할까?

 

 

세 가지 방법이 존재한다.

 

1. 필드명 매칭

조회된 빈들 중에서 자동주입이 되어야 하는 필드 변수의 이름과 같은 이름의 빈이 있다면 이 빈을 우선적으로 등록한다.

@Component
public class OrderServiceImpl implements OrderService{

    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;

    @Autowired  // 파라미터 변수명 rateDiscountPolicy
    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy rateDiscountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = rateDiscountPolicy;
    }
}

타입은 DiscountPolicy 이지만 생성자의 파라미터 이름은 rateDiscountPolicy 이다.

조회된 빈들(fixDiscountPolicy, rateDiscountPolicy) 중 필드명과 이름이 같은 빈인 rateDiscountPolicy 가 우선적으로 주입되게 된다.

(생성자 주입이 아닌 필드 주입을 사용하는 경우에도 동일하게 적용된다.)

 

 

2. @Qualifier

public class BlahBlah {
    private final DiscountPolicy discountPolicy
    
    @Autowired
    public BlahBlah(@Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {
        this.discountPolicy = discountPolicy;
    }
}
.
.
@Component
@Qualifier("fixDiscountPolicy")
public class FixDiscountPolicy implements DiscountPolicy {
}
.
.
@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy {
}

@Qualifier는 의존성 주입에 있어 추가적인 구분 방법일 뿐 빈 이름을 변경하는 것은 아니라는 것에 주의하자

(@Qualifier 역시 필드 주입에서도 사용 가능하다)

 

만약 @Qualifier("mainDiscountPolicy") 가 일치하는 빈을 찾지 못한다면 차선책으로 빈 이름이 mainDiscountPolicy인 빈을 찾는다.

(이 기능은 굳이 사용되게 하지 않도록 하는 것이 좋다)

 

@Qualifier 는 ComponentScan 이 아닌 @Bean 직접 등록할 때에도 달아넣을 수 있다.

 

(추가)

Lombok의 @RequiredArgsConstructor 을 사용해서 생성자를 만들 경우 @Qualifier를 사용하지 못한다.

@RequiredArgsConstructor 는 어노테이션까지 포함해 생성자를 만들 수 없다.

www.inflearn.com/questions/71872

위 링크에 @RequiredArgsConstructor과 @Qualifier를 같이 사용할 수 있는 방법이 나와있지만 귀찮으니 그냥 같이 쓰지는 말자

 

 

3. @Primary  (자주 사용함, 편하지만 한계점이 있다)

그냥 우선순위를 주고 싶은 빈의 클래스에 @Primary 를 달아주면 된다.

@Autowired
private DiscountPolicy discountPolicy
.
.
@Component
public class FixDiscountPolicy implements DiscountPolicy {
}
.
.
@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {
}

 

 

만약 @Primary와 @Qualifier가 겹치는 상황이 발생한다면?

-> @Qualifier가 우선된다.

 

스프링은 항상 포괄적인 개념보다는 상세한 개념을 우선시 한다.

(수동등록 > 자동등록 처럼)

+ Recent posts