개발/spring
스프링 빈 주입 시 우선 순위
방푸린
2024. 11. 12. 17:35
반응형
스프링에서 "빈(Bean)"이란?
- 스프링 IoC(Inversion of Control) 컨테이너에 의해 관리되는 객체
- 빈은 스프링 애플리케이션의 핵심 구성 요소로, 애플리케이션에서 필요한 객체를 컨테이너가 생성하고 관리
- 빈은 컨테이너에 의해 자동으로 주입됨
빈 주입 시 우선순위와 규칙
- 빈 이름 우선순위:
- @Bean(name="beanName")을 사용해 명시적으로 이름을 지정하면, 이 이름이 가장 높은 우선순위를 갖음
- 이름이 지정되지 않은 경우, 메서드 이름이 기본적으로 빈 이름으로 사용
- 같은 이름을 가진 빈이 여러 개 등록되면, 스프링은 중복으로 인식해 오류를 발생시키므로 빈 이름은 고유해야
- 타입 우선순위:
- 빈 주입 시 이름을 명시하지 않고 타입을 사용하여 주입하면, 스프링은 해당 타입에 맞는 빈을 찾음
- 스프링 컨텍스트에 같은 타입의 빈이 여러 개 있을 경우, @Primary 어노테이션을 사용하여 우선순위를 지정할 수 있음. @Primary로 지정된 빈이 기본적으로 선택됨
- @Qualifier("beanName")을 사용하여 특정 이름의 빈을 지정하면, @Primary와 관계없이 해당 이름의 빈이 주입
- @Primary와 @Qualifier 우선순위:
- @Primary는 같은 타입의 빈이 여러 개 있을 때 기본 빈을 지정하는 데 사용됨
- @Qualifier가 지정되면 @Primary보다 우선하여 지정된 이름의 빈을 주입. 즉, @Qualifier가 있으면 @Primary가 무시됨!
- 함수명과 빈 등록 순서:
- @Bean을 사용하는 경우, 메서드 이름이 빈 이름이 됨. 따라서 @Bean(name="beanName")을 명시하지 않으면 메서드명이 빈 이름으로 사용됨.
- XML 설정을 사용할 경우, <bean> 태그에서 id 속성으로 이름을 지정하지 않으면 클래스 이름의 첫 글자를 소문자로 변환한 이름이 빈 이름으로 사용됨.
- 빈 등록 순서가 중요할 때는 @DependsOn을 사용하여 특정 빈이 먼저 초기화되도록 순서를 지정할 수 있음.
사용 예시
@Configuration
public class AppConfig {
@Bean
public Service defaultService() {
return new ServiceImpl();
}
@Bean
@Primary
public Service primaryService() {
return new PrimaryServiceImpl();
}
@Bean(name = "customService")
public Service customNamedService() {
return new CustomServiceImpl();
}
}
이렇게 등록된 빈들을 사용할 때는 아래와 같이 다양한 방법으로 사용할 수 있다.
주의해야 할 점은 이름만 같게 해 준다고 자동으로 주입되는 게 아니라는 사실...
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
public class ServiceConsumer {
private final Service defaultService;
private final Service primaryService;
private final Service customService;
// 기본 주입: @Primary가 지정된 빈이 주입됨
@Autowired
public ServiceConsumer(Service primaryService) {
this.primaryService = primaryService;
}
// @Qualifier를 사용하여 이름으로 주입
@Autowired //setter 방식으로 주입 시 필수
public void setDefaultService(@Qualifier("defaultService") Service defaultService) {
this.defaultService = defaultService;
}
// @Qualifier를 사용하여 특정 이름의 빈 주입
@Autowired
@Qualifier("customService") //메서드에 붙여도 되지만 인자에 붙이는게 더 읽기 쉬움
public void setCustomService(Service customService) {
this.customService = customService;
}
public void useServices() {
primaryService.execute(); // PrimaryServiceImpl이 실행됨
defaultService.execute(); // ServiceImpl이 실행됨
customService.execute(); // CustomServiceImpl이 실행됨
}
}
하지만 내가 선호하는 방식은 아니다. 주입하는 코드가 너무 난잡하고 길다.. 나라면 아래처럼 생성자 방식으로 주입할 것이다...
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
public class ServiceConsumer {
private final Service defaultService;
private final Service primaryService;
private final Service customService;
// 필드에 특정 빈을 주입할 수 있도록 생성자 파라미터에 @Qualifier 추가
public ServiceConsumer(
@Qualifier("defaultService") Service defaultService,
@Qualifier("primaryService") Service primaryService, //@Primary라서 @Qualifier 없어도 됨
@Qualifier("customService") Service customService
) {
this.defaultService = defaultService;
this.primaryService = primaryService;
this.customService = customService;
}
// 메서드 예시
public void useServices() {
defaultService.execute();
primaryService.execute();
customService.execute();
}
}
위처럼 해도 되지만 사실 진짜 원하는건 아래와 같이 롬복을 사용한 방식이다.
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor
public class ServiceConsumer {
private final Service primaryService;
@Qualifier("defaultService")
private final Service defaultService;
@Qualifier("customService")
private final Service customService;
...
}
하지만 이러면 에러가 난다.
Lombok does not copy the annotation 'org.springframework.beans.factory.annotation.Qualifier' into the constructor
꼭 써야한다면..
src/main/java 하위에(com.xx~과 같은 위치) lombok.config 파일을 생성하고 아래 내용을 작성한다.
# lombok.config
lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier
이렇게 설정하면 Qualifier를 복사하여 어노테이션을 롬복이 컴파일할 때 만드는 파일에 추가해 준다.
728x90
반응형