[Spring] 의존 관계 자동 주입( Autometic Dependency Injection) - NoUniqueBeanDefinitionException
조회 대상 빈이 2개 이상일 때는 NoUniqueBeanDefinitionException 예외가 발생하게 된다.
이 때는 3가지 해결 방법이 있다.
- @Autowired 필드명으로 매칭
- @Qualifier -> @Qualifier끼리 매칭 -> 빈 이름 매칭
- @Primary 사용
1️⃣ @Autowired
@Autowired 는 먼저 타입(Type)으로 Bean을 조회하게 되는데, 이때 동일 타입의 빈이 다수 있으면
필드 이름, 파라미터 이름으로 빈 이름을 추가 비교한다.
2️⃣ @Qualifier
1. @Qualifier는 @Qualifier를 찾는 용도로만 사용하는게 명확하다
2. 빈 이름 매칭
3. 없으면 NoUniqueBeanDefinitionException 예외 발생
4. 주입 받을 때, 모든 코드에 @Qualifier를 붙여주어야 한다는 단점이 있다.
5. 치명적으로 @Qualifier(" ")안에 오타가 있을 시 컴파일시 타입 체크를 못한다.
(@Qualifier 안 참조 메서드 이름이 String type으로 되어 있으므로)
=> 해결방법 : Annotation으로 만든다.
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier("mainSalesPolicy")
public @interface MainSalesPolicy {
}
@Component
//@Qualifier("mainSalesPolicy")
@MainSalesPolicy
public class ExtraSalesPolicy implements SalesPolicy {}
Annotation에는 상속이라는 개념이 없다.
이렇게 여러 Annotation을 모아 사용하는 기능은 스프링이 지원해주는 기능이다.
@Qulifier 뿐만 아니라 다른 Annotation들도 함께 조합해서 사용할 수 있다.
3️⃣ @Primary
1. @Autowired시, 빈이 여러개 매칭되면 @Primary가 붙은 것을 우선적으로 조회를 한다.
📢 우선 순위
@Primary는 기본값처럼 동작하는 것이고, @Qualifier 는 매우 상세하게 동작한다. 이런 경우 어떤 것이 우선권을 가져갈까? 스프링은 자동보다는 수동이, 넒은 범위의 선택권보다는 좁은 범위의 선택권이 우선 순위가 높다. 따라서 여기서도@Qualifier가 우선권이 높다.