🌿
@Qualifier,@Primary
- 같은 타입의 Bean이 중복된 경우 해결하기 위해 사용하는 Annotation
🎯 Bean 충돌 해결 방법
1️⃣ @Autowired + 필드명 사용
public interface MyService { ... }
@Component
public class MyServiceImplV1 implements MyService { ... }
@Component
public class MyServiceImplV2 implements MyService { ... }
@Component
public class ConflictApp {
// 필드명을 Bean 이름으로 설정
@Autowired
private MyService myServiceImplV2;
...
}
→ Spring은 타입이 같을 경우 → 필드명 or 파라미터명을 기준으로 주입
2️⃣ @Qualifier 사용 – 별명 붙이기
@Component
@Qualifier("firstService")
public class MyServiceImplV1 implements MyService { ... }
@Component
@Qualifier("secondService")
public class MyServiceImplV2 implements MyService { ... }
@Component
public class ConflictApp {
private MyService myService;
// 생성자 주입에 구분자 추가
@Autowired
public ConflictApp(@Qualifier("firstService") MyService myService) {
this.myService = myService;
}
// setter 주입에 구분자 추가
@Autowired
public void setMyService(@Qualifier("firstService") MyService myService) {
this.myService = myService;
}
...
}
→ Bean 등록 시 추가 구분자를 붙여 줌
→ 특정 Bean에 이름표를 붙이고 그 이름으로 주입
→ 생성자 주입, setter 주입 사용 가능
🧠 용도:
3️⃣ @Primary 사용 – 기본 우선순위 지정
@Component
public class MyServiceImplV1 implements MyService { ... }
@Component
@Primary
public class MyServiceImplV2 implements MyService { ... }
@Component
public class ConflictApp {
private MyService myService;
@Autowired
public ConflictApp(MyService myService) {
this.myService = myService;
}
...
}
→ @Primary는 하나만 지정 가능
→ Qualifier가 붙은 경우가 우선
💬 실제 사례
| 상황 | 사용 방법 |
|---|---|
| MySQL과 Oracle DB 동시 사용 | MySQL → @Primary / Oracle → @Qualifier("oracle") |
| 여러 구현체 중 하나 기본 지정 | 기본 → @Primary, 나머지 → @Qualifier |
🧺 여러 Bean을 한꺼번에 주입하는 방법
@Autowired
private List<MyService> services;
@Autowired
private Map<String, MyService> serviceMap;
→ 모든 Bean을 리스트 또는 맵으로 주입받을 수 있음
→ Bean 이름 → Map의 키로 사용됨
🚀 수동 VS 자동
✅ 자동 등록 (@Component 기반)
| 방법 | 설명 |
|---|---|
@Component, @Service, @Repository, @Controller | 클래스에 어노테이션을 붙이면 자동으로 Bean 등록 |
@ComponentScan | 설정 클래스에서 자동 탐색 범위 지정 |
| Spring Boot | @SpringBootApplication은 내부적으로 @ComponentScan 포함 |
🤖 장점
⚙️ 수동 등록 (@Configuration + @Bean)
| 상황 | 예시 |
|---|---|
| 외부 라이브러리 객체 | new로 만든 객체를 Bean으로 등록 |
| 기술적 설정 (DataSource, TransactionManager 등) | 환경 설정 파일에 명시적으로 등록 |
| Bean 충돌 우려 시 | 명시적으로 선택해서 등록 |
⚠️ Bean 충돌 시 우선순위
| 상황 | 우선순위 |
|---|---|
| 수동 vs 자동 | 수동이 우선 |
@Primary vs @Qualifier | @Qualifier가 우선 |
| 중복 이름 등록 | ❌ 오류 발생 (ConflictingBeanDefinitionException) |
🔧 Spring Boot에서는 기본적으로 충돌 시 오류 발생
→ 설정으로 허용 가능:
spring.main.allow-bean-definition-overriding=true