장쫄깃 기술블로그

[Spring Boot] 의존성 주입 시 Bean이 여러개라면? (@Primary, @Qualifier) 본문

Spring Framework/Spring Boot

[Spring Boot] 의존성 주입 시 Bean이 여러개라면? (@Primary, @Qualifier)

장쫄깃 2022. 6. 26. 00:52
728x90


들어가며


@AutowiredComponent Scan + @Component로 스프링 빈에 등록된 객체를 찾아서 필요한 의존관계를 설정한다. (우선적으로, 타입(Type)으로 해당 빈(Bean)을 찾는다.)

 

만약 @Autowired를 통한 자동 의존관계 주입 시 여러개의 빈이 존재한다면 어떻게 될까? 어떤 빈을 의존주입을 해야할 지 판단하지 못하는 경우 UnsatisfiedDependencyException 이 발생한다. UnsatisfiedDependencyException은 예외명에서도 알 수 있듯이 스프링 빈 객체들이 생성되는 과정에서 의존주입을 하게 되는데, 필드에 해당하는 의존관계를 만족시킬 수 없을 때 발생하는 예외이다.

 

그 중에서 대표적으로 NoUniqueBeanDefinitionException 가 있다.

 

@public class UserWebServiceImple {
	@Autowired private UserService userService;
}

 

위와 같은 경우 UserService 타입의 구현체가 여러 개 존재하고 스프링 컨테이너에 빈으로 등록되어 있는 경우 스프링 컨테이너는 어떤 UserService를 의존주입해야 할 지 판단하지 못하기 때문에 NoUniqueBeanDefinitionException (유일하지 않은 빈 정의 예외)가 발생한다.

 

이러한 상황을 해결할 수 있는 3가지 방법에 대해서 설명해보려고 한다.

 

 

1. @Autowired 필드명 매칭


@Autowired는 우선적으로 타입(Type)으로 빈을 찾지만, 찾지 못하면 필드 이름으로 찾는 특징이 있다. 때문에, 내가 의존성 주입을 받는 필드 이름을 구현체의 이름으로 명시하여 찾게하는 방법이 있다.

 

@Autowired UserRepository userRepository;
@Autowired BoardRepository boardRepository;

 

@Autowired UserRepository vipUserRepository;
@Autowired BoardRepository noticeBoardRepository;

 

필드의 이름을 인터페이스가 아닌 실제 원하는 구현체의 이름으로 적용하는 방법이다. (vipUserRepository, noticeBoardRepository 등) 이렇게 필드명을 원하는 구현체와 일치시키면 여러개의 빈을 찾을 때 해결이 가능하다.

 

하지만 추천하는 방법은 아니다!

 

 

@Primary


@Primary 는 어노테이션을 붙혀서 우선순위를 지정할 때 사용한다. 특정 빈을 우선적으로 주입하고 싶은 경우 해당 어노테이션을 붙여준다.

 

@Component
@Primary
public class noticeBoardRepository implements boardRepository {
	// ...
}

 

@Component
public class galleryBoardRepository implements boardRepository {
	// ...
}

 

@Autowired boardRepository boardRepository; // noticeBoardRepository 빈 의존성이 주입됨!

 

@Primary 어노테이션을 붙혀 @Autowired 시 우선적으로 빈을 찾게 하면, 여러개의 빈을 찾을 때 원하는대로 해결이 가능하다.

 

실무에서 많이 사용하는 방법이다!

 

 

@Qualifier


@Qualifier(빈의 구분자) 는 빈에 구분자를 같이 삽입하여 사용할 의존 객체를 선택할 수 있도록 해준다.

 

@Qualifier("noticeBoardReposiroty")
@Component
public class noticeBoardRepository implements boardRepository {
	// ...
}

 

@Qualifier("noticeBoardRepository")
@Autowired
BoardRepository boardRepository

 

해당 @Qualifier가 붙은 빈을 조회한다. 만약 빈을 찾지 못하면 필드 또는 파라미터 이름으로 매칭을 시도한다. 그래도 찾지 못하면 NoSuchBeanDefinitionException 가 발생한다.

 

@Qualifier를 붙이지 안아도 빈을 찾을 수는 있지만, 유지보수 시 혼란이 생길 수 있으므로 되도록이면 붙여주는 것이 좋다.

 

 

정리하며


@Primary와 @Qualifier를 적절히 사용하는 것이 가장 이상적이다.

  • @Primary는 하나의 구현체만을 사용하게 하는 것
  • @Qualifier는 @Primary보다 귀찮지만, 디테일하게 접하고 사용할 수 있음
    • @Qualifier가 @Primary보다 우선순위가 높다!

 

(의도적으로 여러개의 빈을 가져와서 동적으로 처리하는 경우 위에 설명한 것 + Map/List 를 사용하면 좋음)

728x90