1. 조회하는 빈이 2개 이상일 때, 발생하는 문제
@Autowired는 Type으로 조회하기 때문에, DiscountPolicy처럼 하위 타입을 2개 이상 가지고 있는 경우에
하위 타입 클래스에 @Component로 의존관계 자동주입을 실행하면 빈 충돌 오류가 발생한다.
2. 빈 충돌 해결방법
- @Autowired 필드 명 매칭
- @Qualifier 매칭
- @Primary 사용
1) @Autowired 필드명 매칭
@Autowired는 Type 매칭을 먼저 시도한다.
이 때, 빈이 여러개 있으면 다음으로 필드명, 파라미터 명으로 빈 이름을 매칭한다.
✅기존 코드
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
- discountPolicy에 하위타입이 2개라 이렇게 의존성 주입을 하면 빈 충돌 오류가 발생한다.
✅필드명 매칭 한 코드
//1) 생성자 파라미터명을 일치 시킨다.
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy rateDiscountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = rateDiscountPolicy;
}
//2) 필드명을 일치 시킨다.
@Autowired private DiscountPolicy rateDiscountPolicy
-빈 충돌 오류를 막으려면, 1번처럼 생성자 파라미터명을 일치 시킬 수도 있고 2번처럼 필드명을 일치 시킬 수도 있다.
2) @Qualifier 사용
예시로, DiscountPolicy 하위 타입인 RateDiscountPolicy와 FixDiscountPolicy에 @Qualifier를 붙여줬다.
충돌이 일어날 대상에 빈 등록시 @Qualifier를 붙여주고 주입할 때, @Qualifier를 붙여준다.
✅하위 타입에 @Qualifier 붙여준 코드
@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
@Qualifier("fixDiscountPolicy")
public class FixDiscountPolicy implements DiscountPolicy {}
- 주로 사용할 할인정책을 mainDiscountPolicy라고 명시해줬다.
✅주입 시 @Qualifier와 함께 등록된 이름 붙여준 코드
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, @Qualifier("mainDiscountPolicy") DiscountPolicy
discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
- 의존성 주입 시, 상위타입 앞에 @Qualifier 애노테이션과 함께 하위타입을 지정해준다.
3) @Primary 사용
우선순위를 적용하는 방법이다.
우선권을 가질 하위타입 클래스에 @Primary를 붙여준다.
✅우선권을 가지는 예시코드
@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {}
✅사용코드
//생성자
@Autowired
public OrderServiceImpl(MemberRepository memberRepository,DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
@Autowired와 @Qualifier를 썼을 때와 달리, 사용코드를 그대로 둬도 우선권이 적용되어 코드 실행 시 정상 작동한다.
@Primary를 사용하는 예시로, 자주 사용하는 메인DB의 커넥션을 획득하는 스프링 빈이 있고 가끔 쓰는 보조 DB 를 적용하는 스프링 빈이 있다고 했을 때, 미리 합의하에 메인DB에 @Primary로 우선권을 지정해주는 경우가 있다.
*참고
@Primary 어노테이션을 사용하면 @Qualifier를 사용하지 않아도 되지만, 같이 사용할 경우 @Qualifier가 더 좁은 범위에서 상세하게 동작하기 때문에 우선권이 생긴다.
3. 어노테이션 직접 만들기
@Qualifier("mainDiscountPolicy")를 사용할 때, 컴파일시 타입 체크가 안된다는 문제가 있다.
이럴 때, 어노테이션을 만들어서 타입체크를 할 수 있도록 해줄 수 있다.
package hello.core.annotataion;
import org.springframework.beans.factory.annotation.Qualifier;
import java.lang.annotation.*;
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER,
ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier("mainDiscountPolicy")
public @interface MainDiscountPolicy {
}
@Target 어노테이션으로 필드명, 메소드명, 파라미터명 등에 어노테이션을 붙일 수 있도록 설정한 것이다.
그리고 @Qualifier("mainDiscountPolicy")를 붙여서 기능을 사용할 수 있도록 한다.
✅직접 만든 어노테이션 사용 예시
@Qualifier를 사용하면서 타입체크가 되도록 어노테이션을 만들었다.
사용법은 @Qualifier와 비슷하다.
@Component
@MainDiscountPolicy
public class RateDiscountPolicy implements DiscountPolicy {}
//생성자 자동 주입
@Autowired
public OrderServiceImpl(MemberRepository memberRepository
,@MainDiscountPolicy DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
하위 타입에 @MainDiscountPolicy를 붙이고 생성자 주입 부에 어노테이션을 한번 더 붙여준다.
*참고
어노테이션을 무분별하게 재정의하면 유지보수성이 저하될 수 있으니 꼭 필요할 때만 만들자.
'인프런 김영한 강의 정리 > 스프링 핵심원리 기본편' 카테고리의 다른 글
스프링 핵심 원리 기본편 - 빈 생명주기 콜백 (0) | 2024.05.07 |
---|---|
스프링 핵심원리 기본편 - 의존관계 자동 주입(5)|조회한 빈이 모두 필요할 때, List, Map (0) | 2024.05.07 |
스프링 핵심원리 기본편 - 의존관계 자동 주입(3)|롬복과 최신 트랜드 (0) | 2024.05.06 |
스프링 핵심 원리 기본편 - 의존관계 자동 주입(2)|옵션처리 (0) | 2024.05.04 |
스프링 핵심원리 기본편 - 의존관계 자동 주입(1)|다양한 의존관계 주입방법 (0) | 2024.05.02 |