-
[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라는 추가 구분자를 붙여주는 방법이다.
- 빈 등록시에 @Qualifier를 추가하기
@Component @Qualifier("mainDiscountPolicy") public class RateDiscountPolicy implements DiscountPolicy {}
- 생성자 자동 주입하기
@Autowired public class OrderService(@Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) { this.discountPolicy = discountPolicy; }
@Qualifier가 매칭 되는 순서는 아래와 같다.
- @Qualifier("mainDiscountPolicy") 끼리 매칭
- 없으면, 빈 이름이 "mainDiscountPolicy"인 경우 매칭
- 없으면, 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