1. 의존관계 자동주입
스프링은 애노테이션 기반의 의존성 주입(DI) 기술을 제공하는데, 대표적인 애노테이션이 바로 @Autowired이다. @Autowired는 해당 애노테이션을 붙인 요소(메서드, 필드)에서 의존하는 객체와 동일한 타입의 빈을 찾아 주입해준다. 즉, 의존관계를 자동으로 주입해준다.
@Autowired는 타입을 기준으로 빈을 조회하기 때문에 동일한 타입의 빈이 2개 이상 존재할 때 아래와 같은 빈 중복 문제가 발생할 수도 있다. 마찬가지로 @Configuration+@Bean 조합으로 수동으로 빈을 등록할 때도 동일하게 발생할 수 있는 문제다.
@Component
public class FixDiscountPolicy implements DiscountPolicy {}
@Component
public class RateDiscountPolicy implements DiscountPolicy {}
@Autowired
private DiscountPolicy discountPolicy // NoUniqueBeanDefinitionException
/**
* NoUniqueBeanDefinitionException: No qualifying bean of type
* 'hello.core.discount.DiscountPolicy' available: expected single matching bean
* but found 2: fixDiscountPolicy,rateDiscountPolicy
*/
2. 문제해결 방법
1) @Autowired 필드명/파라미터명 매칭
@Autowired는 빈을 조회할 때 타입 매칭을 먼저 시도하고, 동일한 타입의 빈이 여러 개 있으며 필드명과 파라미터명으로 빈이름과 매칭해본다.
@Autowired
private DiscountPolicy rateDiscountPolicy // 정상적으로 빈이 주입된다.
@Autowired 정리
- 타입 매칭
- 타입 매칭의 결과가 2개 이상일 때 필드명/파라미터명으로 빈 이름 매칭
2) @Qualifier 사용
@Qualifier는 추가 구분자를 붙여주는 방법이다. 실제로 빈 이름을 변경하지는 않는다.
@Component
@Qualifier("fixDiscountPolicy")
public class FixDiscountPolicy implements DiscountPolicy {}
@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy {}
@Autowired
@Qualifier("mainDiscountPolicy")
private DiscountPolicy discountPolicy // 정상적으로 빈이 주입된다.
마찬가지로 수동으로 빈을 등록할 때에도 사용할 수 있다.
@Bean
@Qualifier("mainDiscountPolicy")
public DiscountPolicy discountPolicy() {
return new ...
}
만약 @Qualifer("mainDiscountPolicy")로 대상을 못 찾으면 mainDiscountPolicy라는 이름의 스프링 빈을 추가로 찾는다. 그러나 이런 용도로 @Qualifer를 사용하는 것은 지양하고, @Qualifer는 @Qualifer를 찾는 용도로만 사용하자.
@Quailfier 정리
- @Qualifier끼리 매칭
- 빈 이름 매칭
- NoSuchBeanDefinitionException 발생
3) @Primary 사용
@Primary는 우선순위를 정하는 방법이다. @Autowired를 이용하여 의존관계가 자동으로 주입될 때, 빈이 여러 개 매칭되면 @Primary가 붙은 빈이 우선권을 가진다.
@Component
public class FixDiscountPolicy implements DiscountPolicy {}
@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {} // 해당 빈이 우선권을 가진다.
@Autowired
private DiscountPolicy discountPolicy // 정상적으로 빈이 주입된다.
@Primary는 기본값처럼 동작하고, @Qualifier는 매우 상세하기 동작한다. 스프링에선 자동보다는 수동이, 넓은 범위의 선택권보다는 좁은 범위의 선택권이 우선 순위가 높다. 따라서 둘 중 @Qualifier가 우선권이 높다.
@Primary가 없어서 적절하진 않지만, 요약하자면 다음 그림과 같다.
3. 참고
'Spring > Spring' 카테고리의 다른 글
[Spring] Reactive Feign에서 커스텀 Serializer/Deserializer 사용하기 (0) | 2023.03.21 |
---|---|
[Spring] @Bean 애너테이션의 name 속성과 value 속성 (0) | 2023.03.07 |
[Spring] 트랜잭션 전파 옵션 (0) | 2022.09.07 |
[Spring] 스프링 트랜잭션 전파와 롤백 (0) | 2022.09.07 |
[Spring] 트랜잭션 AOP 사용 시 주의점 (ft. Spring AOP self-invocation) (0) | 2022.09.01 |