[기본기] 7-7. @Qualifier, @Primary

khyojun·2022년 10월 6일
1
post-thumbnail

본 게시글은 김영한님의 스프링 핵심 원리 기본편을 정리한 글입니다.


우선 이 목차를 시작하기 전에 강의에서는 롬복에 대한 사용법을 알려주신다. 그치만 이것은 이전에 velog에서 정리한 내용이 있으므로 롬복 관련 글 을 참고하고 더 필요한 내용이 있으면 검색을 더 해보자.

📌 @Autowired를 하지만 만약 조회되는 빈이 2개 이상이라면?

위의 경우처럼 되면 어떤 오류를 반환하게 될까? 한 번 알아보기 위하여서 위와 같은 코드들에 @Component를 달았다.

@Component
public class RateDiscountPolicy implements DiscountPolicy


@Component
public class FixDiscountPolicy implements DiscountPolicy

우리가 이전에도 말했던 것처럼 @Autowired는 주입관계를 찾을때 .getBean(타입)을 찾는것과 같다. 그래서 위와 같이 우리가 찾을때 만약 주입을 하게 된다면 중복이 되니 오류가 뜰거다.
No qualifying bean of type 'practicecore.ptcore.discount.DiscountPolicy' available: expected single matching bean but found 2: fixDiscountPolicy,rateDiscountPolicy
이렇게 뜰건데 그러면 만약 내가 똑같은 타입이 여러개 있는 빈이 있을때 타입으로 조회하지 않고 하는 방법도 당연히 자동의존관계주입에도 있을 것이다. 근데 또 생각할것이 만약 이걸 추상화타입이 아니라 구현체타입으로 조회를 한다고 한다면 이건 DIP를 어기는 행위가 된다. 그리고 유연성도 떨어지게 되는데 다른 해결방법으로 어떻게 해결할 수 있는지 확인해보자.

@Autowired 필드 명, @Qualifier, @Primary

하나씩 한 번 살펴보자.

@Autowired 필드 명

말 그래도 필드 명으로 찾는 방법인데

@Autowired
private DiscountPolicy rateDiscountPolicy;

뭐 이런 코드가 있다고 하는데 위에처럼 빈에는 두 가지의 할인 정책 둘 다 등록이 되어있다고 하였을때 @Autowired가 매칭을 시키는 방법이 다음과 같다고 한다.
1. 타입끼리 매칭
2. 타입 매칭의 결과가 2개 이상일 때 필드 명, 파라미터 명으로 빈 이름을 매칭.

그래서 rateDiscountPolicy라는 것이 주입이 되어있기도 하기에 타입 매칭의 결과가 2개 이상이므로 rateDiscountPolicy를 매칭을 시킨다는것을 알 수 있다.

@Qualifier

@Component
@Qualifier("mainDiscountPolicy")

@Component
@Qualifier("rateDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy

이런식으로 @Qualifier라는 어노테이션을 추가한 후 구분자를 추가하는 것이지 빈의 이름을 바꾸는 것은 아니다. 그리고 기존에 주입하는 코드에

@Autowired
    public OrderServiceImpl(MemberRepository memberRepository,@Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) { // impl 입장에서는 외부에서 의존성 주입 DI
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
   }

다음과 같이 파라미터에 @Qualifier를 넣어서 이제 검색을 하게 되는데 만약 mainDiscountPolicy라는 것이 없다면 어떻게 처리를 하게 될까?
이렇게 될 경우에는 mainDiscountPolicy라는 이름의 스프링 빈이 있는지 추가로 찾는다고 한다. 여기서 중요한 것이 @Qualifier라는 기능을 사용할때는 "에라~ 모르겠다." 하면서 있든 없든 스프링 빈에 있으면 되겠지 하고 사용하는 것이 아니라 빈이 중복이 될때 기능을 주로 사용해야한다는 것이다. 즉 한마디로 하면 @Qualifier가 존재하지 않는 친구를 스프링 빈에서 찾기위하여 이 기능을 사용하는 것은 좀... 배보다 배꼽이 크다는 느낌이 크다.

그리고 또 이렇게 자동 주입뿐만이 아닌 직접적으로 빈을 등록할때도 @Qualifier를 사용할 수 있다고 한다.

@Bean
@Qualifier("rateDiscountPolicy")
public DiscountPolicy discountPolicy(){
	return new RateDiscountPolicy();
}

자 그럼 Qualifier가 어떻게 찾는지 정리해보면
1. @Qualifier끼리 매칭
2. 없으면 스프링 빈 이름을 매칭
3. NoSuchBeanDefinitionException 예외 발생

@Primary

primary는 한 마디로 정리하면 동일한 타입의 빈 2개가 있을때 우선순위를 부여하여 @Primary가 붙은 빈을 불러온다는 것이다.

@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy


@Component
public class FixDiscountPolicy implements DiscountPolicy

이렇게 되면 RateDiscountPolicy가 우선수위가 높아 매칭이 된다는 것이다. @Qualifier처럼 주입을 하는 곳에서 다 작성해줄 필요 없이 @Primary 하나만 작성하면 된다는 것이 참 좋은 거 같다.

@Qualifier Vs @Primary

그렇다면 이 2개 중 어떤 것이 더 좋은 것?일까? 이것에 대한 예시로서 이제 데이터베이스의 커넥션을 획득하는 예시를 들어주셨다.

코드에서 자주 사용하는 메인 데이터베이스의 커넥션을 획득하는 스프링 빈이 있고, 코드에서 특별한 기능으로 가끔 사용하게 되는 서브 데이터베이스의 커넥션을 획득하는 스프링 빈이 있다고 생각을 하였을때는 메인 데이터베이스의 커넥션을 획득하는 스프링 빈은 @Primary를 적용해서 조회하는 곳에서 @Qualifier 지정 없이 편리하게 조회를 하고, 서브 데이터베이스 커넥션 빈을 획득할 때는 @Qualifier를 지정해서 명시적으로 획득 하는 방식으로 사용하여 코드를 깔끔하게 유지를 할 수 있는데 뭐 어떻게 등록하든 자기 마음이다.

뭐 이런 것만 본다면 각 용도에 맞게 사용하면 되지만 그러면 만약에 둘 다 사용하는 경우가 있으면 어떤 것이 우선권을 가져갈까? 정답으로는 @Qualifier라고 한다. 왜냐? 이전에도 말했던 적이 있던 거 같은데 스프링에서는 자동보다는 수동이, 넓은 범위의 선택권 보다는 좁은 범위의 선택권이 우선되는 것처럼 실제로 @Primary는 기본값처럼 동작을 하고 @Qualifier는 매우 상세하게 동작한다고 한다. 그러므로 @Qualifier 승!

오늘의 결론

@Qualifier @Primary 다 좋은 친구들이지만 상황에 맞게 구분하여 사용할 수 있도록 하자.

출처

  1. 김영한님의 스프링 핵심 원리 기본편(https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8)
profile
코드를 씹고 뜯고 맛보고 즐기는 것을 지향하는 개발자가 되고 싶습니다

0개의 댓글