[Spring] 같은 타입의 빈 문제 해결 방법(@Primary, @Qualifier)
2023. 2. 15. 21:57
스프링은 빈과 연관된 의존관계를 주입할 때 스프링 컨테이너에서 해당 빈을 조회해서 의존관계를 주입한다.
만약, 같은 타입의 빈이 두 개 이상 존재하면 스프링은 의존관계를 주입할 때 어떤 빈을 주입해야 할지 모르기 때문에 애플리케이션은 실행되지 않는다.
Animal 인터페이스와 이를 구현한 Cat, Dog 클래스가 있고 AnimalService에서 Animal을 주입받는다고 가정하면 콘솔에 다음과 같이 나온다.
Animal
package hello.core.animal;
public interface Animal {}
Cat
package hello.core.animal;
import org.springframework.stereotype.Component;
@Component
public class Cat implements Animal{
}
Dog
package hello.core.animal;
import org.springframework.stereotype.Component;
@Component
public class Dog implements Animal{
}
AnimalService
package hello.core.animal;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class AnimalService {
private final Animal animal;
}
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in hello.core.animal.AnimalService required a single bean, but 2 were found:
- cat: defined in file [~\Cat.class]
- dog: defined in file [~\Dog.class]
Action:
Consider marking one of the beans as @Primary,
updating the consumer to accept multiple beans,or
using @Qualifier to identify the bean that should be consumed
Process finished with exit code 1
위와 같이 3가지 방법을 사용하라고 한다.
1. @Primary
@Primary는 우선순위를 지정하는 어노테이션이다.
의존관계 주입 시 여러 개의 빈이 매칭되면 @Primay를 적용한 빈이 우선권을 갖게 된다.
@Primary
@Component
public class Dog implements Animal{
}
2. @Qualifier
@Qualifier는 추가 구분자를 붙여주는 방법이다. 별명처럼 추가적인 방법을 제공하는 것일 뿐 빈 이름을 변경하는 것이 아니다.
@Service
//@RequiredArgsConstructor
//롬복 사용시 @Qualifier를 사용하기 위해선 추가적인 설정이 필요하기 때문에 주석 처리
public class AnimalService {
private final Animal animal;
public AnimalService(@Qualifier("dogdog") Animal animal) {
this.animal = animal;
}
}
3. 여러 개의 빈을 한 번에 받기(updating the consumer to accept multiple beans)
의도적으로 여러 개의 빈이 필요할 때 사용한다.
스프링에서는 Collection 주입을 지원해 주기 때문에 같은 타입의 여러 빈이 존재하거나 필드나 파라미터 변수의 타입이 Collection, List, Map 일 경우 컬렉션으로 넘겨주어 한 번에 의존 관계를 맺게 해 준다.
@Slf4j
@Service
@RequiredArgsConstructor
public class AnimalService {
private final Map<String,Animal> animal;
@PostConstruct
public void init() {
log.info("animal = {}", animal);
}
}
//animal = {cat=hello.core.animal.Cat@29138d3a, dog=hello.core.animal.Dog@5cbe2654}
참고 자료 : 김영한님 스프링 핵심 원리 - 기본편
'Programming > Spring' 카테고리의 다른 글
[Spring] HttpServletRequest 요청마다 같은 주소값을 반환하는 이유 (0) | 2023.02.25 |
---|---|
[Spring] RequestContextHolder를 통해 HttpServletRequest, Response 가져오기 (0) | 2023.02.17 |
[Spring] 스프링 컨테이너와 빈 (0) | 2023.02.13 |
[Spring] 예외처리 - ExceptionHandler, ControllerAdvice (0) | 2022.10.30 |
[Spring] Spring MVC 구조 (0) | 2022.10.25 |