스프링에서 자동 의존성 주입을 사용할 때, 같은 타입의 빈이 여러 개 조회되는 상황에 도움이 되는 몇 가지에 대해 알아보자.
목차
- @Autowired
- @Qualifier
- @Primary
- 같은 타입의 빈을 모두 조회하고싶다면?
@Autowired
의존성 자동 주입에 사용되는 애노테이션인 @Autowired는 먼저 애노테이션이 적용된 필드, 파라미터의 타입을 기준으로 빈을 조회한다.
같은 타입의 빈이 여러 개 조회되면 추가적으로 필드 또는 파라미터의 이름으로 빈을 조회한다.
다음과 같이 HelloService 인터페이스와 두 개의 구현체가 있다.
public interface HelloService {
String hello();
}
@Component
public class HelloServiceEng implements HelloService{
@Override
public String hello() {
return "Hello";
}
}
@Component
public class HelloServiceKor implements HelloService {
@Override
public String hello() {
return "안녕";
}
}
HelloService 타입으로 자동 의존성 주입을 시도하면 구현체가 2개이기 때문에 예외가 발생한다.
(예제 코드에서는 필드 주입을 사용하였다. 생성자 주입, 수정자 주입에서도 결과는 동일)
@Autowired HelloService helloService;
필드 이름을 helloServiceKor로 바꾸면 HelloServiceKor 구현체가 주입된다.
//HelloServiceKor이 주입된다.
@Autowired HelloService helloServiceKor;
@Qualifier
@Qualifier 애노테이션을 사용하여 추가적인 구분자를 사용할 수 있다. 사용 방법은 빈을 등록할 때, 빈을 주입할 때 @Qualifier 애노테이션에 구분에 사용할 문자열을 전달하여 사용하면 된다.
@Component
@Qualifier("mainHelloService")
public class HelloServiceKor implements HelloService {
@Override
public String hello() {
return "안녕";
}
}
//또는 빈을 직접 등록할때도 사용 가능.
@Bean
@Qualifier("mainHelloService")
빈을 주입 시에도 동일하게 같은 이름을 전달하여 해당 빈이 주입되도록 한다.
//필드 주입 예시
@Autowired
@Qualifier("mainHelloService")
HelloService helloService;
//생성자 주입 예시
public HelloController(
@Qualifier("mainHelloService") HelloService helloService) {
this.helloService = helloService;
}
의존성을 주입할 때 @Qualifier("mainHelloService")를 선언한 빈이 없다면? mainHelloService라는 이름의 빈을 추가로 찾는다. 그래도 찾을 수 없다면 NoSuchBeanDefinitionException이 발생한다.
@Primary
@Primary의 사용법은 정말 간단하다. 우선권을 갖고자하는 빈에 애노테이션을 붙여주면 된다.
@Component
@Primary
public class HelloServiceEng implements HelloService{
@Override
public String hello() {
return "Hello";
}
}
HelloService 타입의 빈 주입 시 HelloServiceEng이 주입된다.
@Autowired
HelloService helloService;
@Test
@DisplayName("HelloServiceEng가 주입된다.")
void helloServiceTest() {
Assertions.assertSame(HelloServiceEng.class, helloService.getClass());
}
//테스트 통과
참고로 스프링에서 자동보다는 수동, 넓은 범위보다는 좁은 범위의 설정이 더 높은 우선순위를 가진다. 따라서 @Primary와 @Qualifier 둘 중에 @Qualifier가 우선순위가 높다.
같은 타입의 빈을 모두 조회하고 싶다면?
- 의존성 주입 시 List 또는 Map을 사용해서 같은 타입의 빈을 한 번에 모두 조회할 수 있다.
@Autowired
Map<String, HelloService> helloServiceMap;
@Autowired
List<HelloService> helloServices;
@Test
@DisplayName("같은 타입의 빈 모두 조회하기")
void helloServiceTest() {
//Map으로 조회
for (String name : helloServiceMap.keySet()) {
System.out.println("name = " + name + ", bean = " + helloServiceMap.get(name));
}
//List로 조회
for (HelloService helloService : helloServices) {
System.out.println("helloService = " + helloService);
}
}
/* 실행 결과
name = helloServiceEng, bean = com.example.springstudy.HelloServiceEng@1867b831
name = helloServiceKor, bean = com.example.springstudy.HelloServiceKor@21f8acfd
helloService = com.example.springstudy.HelloServiceEng@1867b831
helloService = com.example.springstudy.HelloServiceKor@21f8acfd
*/
참고
'Spring' 카테고리의 다른 글
[스프링 MVC] 요청 파라미터 조회하기 - @RequestParam, @ModelAttribute (0) | 2021.07.07 |
---|---|
[스프링] 프록시(Proxy) (0) | 2021.03.08 |
[스프링] 의존관계 조회(Dependency Lookup) : ObjectFactory, ObjectProvider, JSR-330 Provider (0) | 2021.03.08 |
[스프링] 빈 초기화, 소멸 메소드 사용하기 (0) | 2021.01.12 |
[스프링] Cookie 사용하기(@CookieValue, HttpServletResponse) (0) | 2020.12.01 |
댓글