Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 스프링 핵심 기능
- 스프링 핵심 원리
- 김영한
- kotlin
- java
- QueryDSL
- SpringBoot
- spring
- http
- Servlet
- AOP
- JPQL
- Android
- Exception
- 인프런
- db
- 스프링
- 그리디
- 알고리즘
- 백준
- Thymeleaf
- pointcut
- springdatajpa
- JDBC
- jpa
- Proxy
- 자바
- Greedy
- Spring Boot
- transaction
Archives
- Today
- Total
개발자되기 프로젝트
조회할 빈이 2개 이상일 경우? 본문
- @Autowired는 타입으로 조회를 한다.
- 근데 스프링 컨테이너에 같은 타입의 빈이 여러 개 있으면..?
1. 같은 타입이 2개!
- DiscountPolicy의 구현체는 2개가 있다.
- RateDiscountPolicy
@Component public class RateDiscountPolicy implements DiscountPolicy{
- FixDiscountPolicy
@Component public class FixDiscountPolicy implements DiscountPolicy{
- 둘 다 @Component등록이 되면 어떻게 될까?
2. Test
public class AutoAppConfigTest {
@Test
void basicScan(){
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class);
MemberService memberService = ac.getBean(MemberService.class);
Assertions.assertThat(memberService).isInstanceOf(MemberService.class);
}
}
- NoUniqueBeanDefinitionException: 예외가 발생한다.
NoUniqueBeanDefinitionException : No qualifying bean of type 'hello.core.discount.DiscountPolicy' available:
expected single matching bean but found 2: fixDiscountPolicy,rateDiscountPolicy
- OrderServiceImpl
OrderServiceImple은 DiscountPolicy를 컨테이너에서 주입을 받는다.@Component @RequiredArgsConstructor //final 붙은 필드를 받는 생성자를 만듦 public class OrderServiceImpl implements OrderService{ private final MemberRepository memberRepository; private final DiscountPolicy discountPolicy;
하지만 DiscountPolicy타입의 빈은 FixDiscountPolicy, RateDiscountPlicy 두 개 가 존재하여 뭐를 가지고 올지..모름. - 어떻게 해야할까...?
- 구체적인 하위 타입의 빈을 지정할 수도 있다. 하지만 하위 타입으로 지정하는 것은 DIP 위반이다! 멈춰!
- 그리고 이름만 다르고 또오오옥같은 스프링 빈이 있을 경우 해결할 수 없음..
- 스프링 빈을 수동으로 등록하여 우선순위를 활용하는 방법도 있겠지만..흠..
3. 자동 관계주입에서 중복 문제 해결
세 가지 방법이 있다.
- @Autowired 필드명 매칭
- @Qualifier
- @Primary
4. @Autowired 필드명 매칭
- @Autowired는 타입 매칭을 시도하고, 여러 빈이 있으면 필드 이름(파라미터 이름)으로 빈 이름을 추가 매칭함!
- 생성자 같은 경우 파라미터 이름을 봄.
- 기존 코드
@Component @RequiredArgsConstructor //final 붙은 필드를 받는 생성자를 만듦 public class OrderServiceImpl implements OrderService{ private final MemberRepository memberRepository; private final DiscountPolicy discountPolicy; //이렇게하면 인터페이스에만 의존함.
DiscountPolicy의 필드명이 discountPolicy로 되어있다. 필드 명을 받고자 하는 구현체의 bean name으로 변경하면
해당 빈을 주입받을 수 있다.
- 변경 코드
@Component @RequiredArgsConstructor //final 붙은 필드를 받는 생성자를 만듦 public class OrderServiceImpl implements OrderService{ private final MemberRepository memberRepository; private final DiscountPolicy rateDiscountPolicy;
- Test
public class AutoAppConfigTest { @Test void basicScan(){ AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class); MemberService memberService = ac.getBean(MemberService.class); Assertions.assertThat(memberService).isInstanceOf(MemberService.class); } }
- 즉 @Autowired로 연결할 타입과 동일한 빈을 자식까지 포함해서 다 끌고옴.
- 어? 같은 타입이 여러개가 있네?
- 필드 이름이뭐임?, 파라미터 명이 뭐임?
- 필드 이름이랑 파라미터 이름이 빈 이름 같은애로 가져올꼐! 메다닥
3. @Qualifier
- 추가 구분자를 붙여주는 방법임.
- 주입 시 추가적인 방법을 제공하지만, 빈 이름을 변경하는 것은 아님!
-
@Component @Qualifier("mainDiscountPolicy") public class RateDiscountPolicy implements DiscountPolicy{
- 그리고 빈을 주입 받을 곳 에서 @Qualifier를 동일하게 붙여주면 된다.
- 그러면 같은 타입 중 "mainDiscountPolicy" 가 붙은 빈을 가지고 온다.
- 어? 근데 lombok이랑 같이 사용을 못해!
- RequiredArgsConstructor를 빼고 생성자를 별도로 만들어서 적용하면 된다.
-
@Component //@RequiredArgsConstructor //final 붙은 필드를 받는 생성자를 만듦 public class OrderServiceImpl implements OrderService{ private final MemberRepository memberRepository; private final DiscountPolicy discountPolicy; //이렇게하면 인터페이스에만 의존함. //private final DiscountPolicy discountPolicy = new RateDiscountPolicy(); @Autowired public OrderServiceImpl(MemberRepository memberRepository, @Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) { this.memberRepository = memberRepository; this.discountPolicy = discountPolicy; }
- 흠 그러면 만약 지정한 이름의 @Qualifier를 못찾으면..?
- mainDiscoutPolicy라는 이름의 스프링 빈을 추가로 찾음..
- 그러니 @Qualifier는 @Qualifier만 찾는 용도로만 사용하자.
- 직접 등록시에도 사용 가능.
4. @Primary
- 우선순위를 정할 수 있다.
- @Autowired시 여러 빈이 매칭되면 @Pairmary가 1등
- RateDiscountPolicy에 @Primay
-
@Component @Primary public class RateDiscountPolicy implements DiscountPolicy{
5. @Qualifier vs @Primary
- @Qualifier의 단점은 주입받을 때 모든 코드에 @Qualifer붙여줘야 함.
- @Primary는 그럴 필요는 없음
- 예를들어 main으로 사용하는 어떤 클래스? 구현체가 있다고 하면 main으로 사용하는 구현체는
@Primary로 등록해놓고, 가끔 서브로 사용하는 구현체는 @Qualifer를 등록
따라서 평상시에는 그냥 쓰다가 sub를 호출하는 메서드에만 @Qualifier를 통해 명시적으로 사용. - 우선순위 : 자세한 것이 우선순위가 높다
- @Primary는 기본 값 처럼 작동, .
- @Qualifier는 이름까지 지정, 우선순위가 더 높음
6. GitHub : 210730 @Qualifier, @Primary
'인프런 > [인프런] Spring 핵심원리 이해' 카테고리의 다른 글
조회한 빈을 리스트, Map으로 받아보자 (0) | 2021.07.30 |
---|---|
@Qualifier, 타입체크, annotaion만들기 (0) | 2021.07.30 |
의존관계 주입, lombok (0) | 2021.07.29 |
생성자 주입을 선택해! (0) | 2021.07.29 |
@Autowired 옵션처리 (0) | 2021.07.29 |
Comments