| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
| 29 | 30 | 31 |
- 다이렉트 레퍼런스
- dfs
- 스프링 컨테이너
- BFS
- aws saa-c03
- 2026 AWS SAA-C03
- stop the world
- 파이썬 문자열 메서드
- 플랫폼 클래스 로더
- 객체지향
- 자료구조
- python list method
- 알고리즘
- 심볼릭 레퍼런스
- 파이썬 리스트 메서드
- Spring
- 코딩테스트
- 딕셔너리
- 파이썬
- AWS SAA-C03 합격후기
- getreference
- 백준
- python
- 자바
- java
- 부트스트랩 클래스 로더
- 어플리케이션 클래스 로더
- 컴포넌트 스캔
- 클래스 로더 계층
- 스프링
- Today
- Total
클라우드 낚시꾼
[Spring] @Autowired 필드명, @Qualifier, @Primary 본문
1. 조회 빈이 2개 이상인 문제
// 1번 코드
@Autowired
private DiscountPolicy discountPolicy
// 2번 코드, ac는 스프링 컨테이너 변수명
ac.getBean(DiscountPolicy.class)
@Autowired는 타입(Type)으로 조회한다. 그렇기에 위의 1번 코드와 2번 코드는 사실상 같은 코드이다.
@Component
public class FixDiscountPolicy implements DiscountPolicy {}
@Component
public class RateDiscountPolicy implements DiscountPolicy {}
//의존관계 자동주입 실행
@Autowired
private DiscountPolicy discountPolicy
DiscountPolicy의 하위 타입인 FixDiscountPolicy, RateDiscountPolicy 둘다 스프링 빈으로 선언하였다. 이 상태에서 의존관계 자동주입을 실행하면, NoUniqueBeanDefinitionException 오류가 발생한다. 이 오류 메시지는 DiscountPolicy 타입으로 빈을 조회했을 때, 조회 결과로 하나의 빈을 기대했지만 fixDiscountPolicy, rateDiscountPolicy 2개의 빈이 발견되었다고 알려준 것이다. 이것이 NoUniqueBeanDefinitionException 오류이다.
@Autowired
private RateDiscountPolicy discounyPolicy
이때, 의존관계 자동주입 코드를 하위 타입으로 지정하여 에러를 막을 수 있다. 하지만, 하위 타입으로 지정하는 것은 DIP를 위배하고 유연성을 떨어지게 한다. 그리고 이름만 다르고 완전히 똑같은 스프링 빈이 2개 있을 때를 해결 할 수 없다. 이제부터 이러한 의존 관계 자동 주입 문제를 해결하는 방법을 알아보자.
2. 조회 대상 Bean이 2개 이상일 때 해결 방법
RateDiscounyPolicy, FixDiscountPolicy가 DiscountPolicy의 하위 타입이라고 가정한다.
#1. @Autowired 필드명
@Autowired의 매칭은 아래와 같이 진행된다.
- 타입 매칭
- 타입 매칭 시 여러 빈이 있으면
- 필드 이름 매칭
- 파리미터 이름 매칭
// 수정 전: 타입 매칭
@Autowired
private DiscountPolicy discountPolicy
// 수정 후: 타입 매칭 후 필드명 매칭 시도
@Autowired
private DiscountPolicy rateDiscountPolicy
수정 전, 수정 후 모두 DiscountPolicy 타입으로 Bean을 조회하기 때문에 Bean이 2개 이상 조회된다. 다음으로, 수정 전 코드는 discountPolicy 필드 이름으로 빈 조회를 시도한다. 이때도 역시 조회 결과로 Bean이 2개 이상 발견되고 최종적으로 NoUniqueBeanDefinitionException이 발생하게 된다. 반면, 수정 후 코드는 rateDiscountPolicy 필드 이름으로 빈 조회를 시도한다. 이때는 최종적으로 1개의 Bean만 조회되기 때문에 성공적으로 Bean 조회가 완료된다.
#2. @Qualifier
// 빈 등록시 @Qualifier로 추가적인 구분자를 붙인다.
@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
@Qualifier("fixDiscountPolicy")
public class FixDiscountPolicy implements DiscountPolicy {}
// 자동 주입 예시
@Autowired
public OrderServiceImpl(MemberRepository memberRepository,
@Qualifier("mainDiscountPolicy") DiscountPolicy
discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
@Qualifier는 스프링 Bean에 추가적인 구분자를 붙여주는 방법이다. @Qualifier는 주입 시 추가적인 방법을 제공하는 것뿐이지 빈 이름을 변경하는 것은 아니다. 의존관계를 주입할 때는 @Qualifier("구분자명")을 명시한다. 하지만, 이때 @Qualifier("구분자명")을 못 찾게 되면 어떻게 될까? @Qualifier("구분자명")으로 매칭이 실패하면 빈 이름으로 매칭을 시도한다. 빈 이름으로도 매칭이 실패하면 NoUniqueDefinitionException이 발생하게 된다.
#3. @Primary
// @Primary가 우선권을 가진다.
@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
public class FixDiscountPolicy implements DiscountPolicy {}
@Primary는 우선순위를 정하는 방법이다. @Autowired 시에 여러 빈이 매칭되면 @Primary이 붙은 @Component가 우선권을 가지게 된다. 위 코드에서 만약, DiscountPolicy 타입으로 조회를 시도하면 RateDiscountPolicy와 FixDiscountPolicy가 매칭될 것이다. 여기서 RateDiscountPolicy에 @Primary가 붙어 있어 우선권을 가지게되므로 최종적으로 조회 결과는 RateDiscountPolicy가 된다.
3. @Primary, @Qualifier 그리고 둘의 우선순위
@Primary를 사용하게 되면, 생성자 코드를 따로 조작할 필요가 없게 되어 편리하다. 그렇기에 좀 더 자주 사용하는 Bean을 @Primary로 등록하고, 좀 더 특별할 때 사용되는 Bean을 @Qualifier로 등록하여 조회하는 것이 권장된다.
// Primary 등록
@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy{}
// @Qualifier("sub") 등록
@Component
@Qualifier("sub")
public class FixDiscountPolicy implements DiscountPolicy{}
// 의존관계 주입
@Component
public class OrderServiceImpl implements OrderService{
private final MemberService memberService;
private final DiscountPolicy discountPolicy;
public OrderServiceImpl(MemberService memberService,
@Qualifier("sub") DiscountPolicy discountPolicy) {
this.memberService = memberService;
this.discountPolicy = discountPolicy;
}
}
위 코드에서 RateDiscountPolicy는 @Primary, FixDiscountPolicy는 @Qualifier("sub")으로 등록되어 있다. 의존관계 주입 시에는 discountPolicy 앞에 @Qualifier("sub")가 붙어있다. 이때, DiscountPolicy 타입으로 스프링 빈을 조회한다면, 어떤 것이 조회될까? 스프링은 자동보다는 수동이, 넒은 범위의 선택권 보다는 좁은 범위의 선택권이 우선 순위가 높다. 따라서 여기서도 @Qualifier가 우선권이 높다. 즉, @Primary와 @Qualifier가 사용되는 상황에서 @Qualifier으로 의존관계 주입을 시도한다면, @Qualifier가 우선권을 가져가게 된다. 물론, @Primary가 단독으로 사용되는 경우에는 @Primary가 우선권을 가져가게 된다.
4. 세줄 요약
1. 스프링 Bean을 조회할 때 기본적으로 타입을 이용한다. 이 때문에 조회 Bean이 2개 이상인 문제가 발생하기도 한다.
2. @Qualifier는 스프링 Bean에 구분자를 붙여 그 구분자로 스프링 Bean을 조회하는 방식이다.
3. @Primary는 스프링 조회 Bean이 2개 이상일 때, 어느 한 쪽에 우선권을 부여하여 Bean을 조회하는 방식이다.
스프링 핵심 원리 - 기본편 강의 - 인프런
스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., 스프링 핵심 원리를 이해하고, 성장하는 백엔드 개발자가 되어보세요! 📢
www.inflearn.com
'BE Framework > SpringBasic' 카테고리의 다른 글
| [Spring] 빈 스코프(singleton, prototype...) (0) | 2024.03.26 |
|---|---|
| [Spring] 스프링 빈 생명주기 콜백 (0) | 2024.03.25 |
| [Spring] Lombok(롬복) 사용하기 (@RequiredArgsConstructor) (0) | 2024.03.19 |
| [Spring] @Autowired(required)와 의존관계 주입 방법 (0) | 2024.03.18 |
| [Spring] 컴포넌트 스캔: 탐색 위치와 기본 스캔 대상 & 필터 (0) | 2024.03.16 |