ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Lombok] @RequiredArgsConstructor에 @Qualifier를 적용하는 방법
    🐳Dev 2023. 5. 21. 02:45

    @RequiredArgsConstructor

    Lombok은 반복적으로 사용되는 생성자와 getter, setter 등의 보일러플레이트 코드를 줄여주는 Java 라이브러리이다. @RequiredArgsConstructor는 이 Lombok에 포함된 어노테이션이다. @RequiredArgsConstructor는 각각의 필드를 매개변수로 가지는 생성자를 만들어준다. 이때 필드는 초기화 되지 않은 final 필드거나 @NonNull이 붙은 필드여야 한다.

    또한 스프링은 "생성자가 딱 1개만 있으면 @Autowired를 생략해도 스프링 빈을 자동 주입된다"는 개념을 사용해 생성자 주입도 깔끔하게 해결할 수 있다.

     

    @Qualifier

    @Autowired는 타입으로 조회한다. 그래서 같은 상위 타입을 가진 여러 개의 구현체를 빈으로 등록하면, 해당 빈이 주입될 때 어떤 구현체를 가져와야 하는지 몰라 에러를 반환한다.

     

    NoUniqueBeanDefinitionException: No qualifying bean of type 'hello.core.discount.DiscountPolicy' available: expected single matching bean but found 2: fixDiscountPolicy,rateDiscountPolicy
    

     

    물론 필요할 때 하나만 생성해서 사용해도 되지만, 만약 두 구현체가 각기 다른 곳에서 사용되는 상황이라면 어떨까?

    이러한 상황을 해결하기 위해 아래 세가지 방법이 존재한다

     

    • @Autowired 필드 명을 빈 이름과 똑같이 만들어 매칭
    • 같은 @Qualifier끼리 매칭
    • @Primary 사용

     

    이 중 @Qualifier를 사용하는 방법을 알아보려고 한다.

    @Qualifier는 단순히 빈에 @Qualifier라는 추가 구분자를 붙여주는 방법이다.

     

    1. 빈 등록시에 @Qualifier를 추가하기
    @Component
    @Qualifier("mainDiscountPolicy")
    public class RateDiscountPolicy implements DiscountPolicy {}
    
    1. 생성자 자동 주입하기
    @Autowired
    public class OrderService(@Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {
          this.discountPolicy = discountPolicy;
    }
    

     

    @Qualifier가 매칭 되는 순서는 아래와 같다.

    1. @Qualifier("mainDiscountPolicy") 끼리 매칭
    2. 없으면, 빈 이름이 "mainDiscountPolicy"인 경우 매칭
    3. 없으면, NoSuchBeanDefinitionException 예외 발생

     

    문제 상황

    문제는 이 둘을 같이 사용하고자 할 때 발생한다.

    @Component
    @RequiredArgsConstructor
    public class OrderService {
    
        @Qualifier("main")
        private final DiscountPolicy discountPolicy;
    
    ...
    }
    

     

    빌드하면 빈을 찾을 수 없다는 에러가 발생한다.

    Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException
    

     

    OrderService 클래스 파일을 열어보면, 생성자의 매개변수에 @Qualifier가 존재하지 않는 걸 볼 수 있다.

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

     

    해결 방법

    이는 lombok의 @RequiredArgsConstructor이 어노테이션을 포함해서 생성자를 만들지 않기 때문이다. 그래서 @Qualifier 어노테이션을 복사할 수 있도록, 직접 롬복 구성 파일에 명시적으로 선언해야 한다.

     

    src/main/java/lombok.config를 생성하고 아래 코드를 추가한다.

    lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier
    

     

    그리고 다시 프로젝트를 컴파일하고, OrderService 클래스 파일을 열어보면 이전과 다르게 매개변수에 어노테이션이 붙어있는 것을 확인할 수 있다.

    public OrderService(final MemberRepository memberRepository, @Qualifier("main") final DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }
    

    '🐳Dev' 카테고리의 다른 글

    TestContainer 적용해보기  (0) 2022.12.05
Designed by Tistory.