@Autowired 어노테이션은 의존성 주입을 위해 생성자 파라미터를 타입으로 조회하기 때문에 Bean 등록 어노테이션(@Component, @Service, @Repository, @Controller)으로 빈으로 등록했을 때 빈이 2개 이상 조회될 수 있습니다.
이번 포스팅에서는 조회 빈(Bean)이 2개 이상일 때 처리하는 방법에 대해서 알아보겠습니다.
사용할 예시 코드
public interface Food {
void eat();
}
@Component
public class Chicken implements Food {
@Override
public void eat() {
System.out.println("치킨을 먹습니다.");
}
}
@Component
public class Pizza implements Food {
@Override
public void eat() {
System.out.println("피자를 먹습니다.");
}
}
Food interface를 구현한 각각의 구현체 음식 food 중 Pizza클래스와 Chicken클래스가 있다고 가정해보겠습니다.
Bean 등록 확인
Pizza와 Chicken 클래스 @Componet 어노테이션 지정하여 Bean으로 등록하고 있습니다.
Bean을 확인을 해보면 chicken과 pizza 두 개가 등록된 것을 볼 수 있습니다.
즉, 등록 자체는 문제가 없습니다.
Bean 2개 이상일 때 에러 발생
@SpringBootTest
public class BeanTest {
@Autowired
Food food;
}
그러나 BeanTest에서 "Food food"필드에 @Autowired를 사용하여 Bean 객체를 주입려고 시도합니다.
그러면 food에 chicken을 주입할지, Pizza를 주입할지 모르기 때문에 에러가 발생합니다.
Could not autowire. There is more than one bean of 'Food' type.
위 에러를 해석해 보자면 “Food 타입의 Bena 객체가 하나 이상 있습니다. “라고 알려주고 있습니다.
즉, food 필드에 Bean을 주입해줘야 하는데 같은 타입의 Bean 객체가 하나 이상이기 때문에 어떤 Bean을 등록해줘야 할지 몰라 오류가 발생한 것입니다.
Bean 2개 이상 문제 해결
조회 Bean이 2개 이상일 때 해결하는 방법은 3가지가 있습니다.
- 등록된 Bean 이름 명시
- @Pirmary 사용
- @Qualifier 사용
1. 등록된 Bean 이름 명시
이렇게 등록된 Bean의 이름 pizza, chicken을 정확하게 명시해 주면 해결할 수 있습니다.
위 경우에는 Bean은 클래스 이름으로 자동으로 생성되었습니다.
여기서 알 수 있는 점은 @Autowired가 기본적으로는 Bean Type(여기서는 : Food)으로 DI를 지원하며 연결이 되지 않을 경우 Bean Name(여기서는 : pizza, chicken)으로 찾는다는 것을 알 수 있습니다.
@Test
@DisplayName("Test")
void test1(){
pizza.eat();
chicken.eat();
}
Test를 해보면 왼쪽 결과와 같이 해당하는 구현체를 주입해 준다는 것을 확인할 수 있습니다.
Bean이름 결정 방식에 자세한 내용은 아래의 포스팅에서 확인하실 수 있습니다.
2. @Primary 사용하기
이때 @Primary 어노테이션을 사용한다면 해결할 수 있습니다.
@Primary 어노테이션은 Spring Framework에서 의존성 주입 시 기본 빈을 선택하는 데 사용되는 어노테이션입니다.
빈이 여러 개 등록되어 있고, 그중 하나를 기본으로 지정하고 싶을 때 @Primary를 사용할 수 있습니다.
@SpringBootTest
public class BeanTest {
@Autowired
Food food;
@Test
@DisplayName("Test")
void test1(){
food.eat();
}
}
@Component
@Primary
public class Chicken implements Food {
@Override
public void eat() {
System.out.println("치킨을 먹습니다.");
}
}
Test를 해보면 현재 Bean Type(food)으로 주입을 했는데, Chicken 구현체를 주입한 것을 확인할 수 있습니다.
3. @Qualifier 사용하기
@Qualifier 어노테이션은 Spring Framework에서 빈 주입 시 여러 개의 빈이 동일한 타입으로 등록되어 있을 때, 특정 빈을 선택하여 주입하는 데 사용됩니다.
즉, @Autowired와 함께 사용하여 빈의 이름을 명시적으로 지정함으로써, 원하는 빈(여기서는 : pizza)을 정확히 주입할 수 있게 도와줍니다.
왼쪽의 test1 실행 결과를 보면 현재 Bean Type(food)으로 주입을 했는데, Pizza 구현체를 주입한 것을 확인 할 수 있습니다.
@Qualifier와 @Primary의 우선순위
만약 같은 타입의 Bean에 @Qualifier와 @Primary가 동시 적용되어 있다면 어떻게 될까요❓
test1의 실행결과를 보면 다음과 같습니다.
즉 같은 타입의 Bean들에 @Qualifier와 @Primary가 동시에 적용되어 있다면 Qualifier의 우선순위가 더 높습니다.
따라서 범용적으로 사용되는 빈에는 @Primary를 설정하고, 지역적으로 사용되는 빈에는 @Qualifier를 사용하는 것이 좋습니다.
이렇게 하면 빈 주입이 명확해지고, 코드의 가독성과 유지 보수성이 향상됩니다.
Spring에서의 우선순위
Spring Framework에서 빈의 우선순위는 범위에 따라 달라집니다.
- 범위에 따른 우선순위
- 좁은 범위 > 넓은 범위
- @Qualifier와 @Primary의 우선순위
- @Qualifier > @Primary
- @Qualifier는 빈의 이름이나 ID를 명시적으로 지정하기 때문에, 같은 타입의 빈 중에서 가장 우선적으로 선택됩니다.
- @Primary는 기본적으로 선택될 빈을 지정하지만, @Qualifier가 명시된 경우에는 @Qualifier의 지정이 우선합니다.
'Framework > Spring\Spring boot' 카테고리의 다른 글
[Spring Boot] Spring Boot에서 JWT 다루기 (JWT, @Value, @PostConstruct) (0) | 2024.07.29 |
---|---|
[Spring MVC]인증과 인가란 ❓, 쿠키와 세션란❓(Authentication, Authorization, @CookieValue, HttpServletEuquest, HttpServletResponse) (0) | 2024.07.29 |
[Spring] Spring에서 빈 이름 결정 방식 (0) | 2024.07.28 |
[Spring] Spring IoC 컨테이너에 Bean 수동 등록하기 (@Configuration, @Bean) (0) | 2024.07.28 |
[Spring] Spring IoC Container와 Bean 알아보기 (0) | 2024.07.24 |