@Component
public class KakaoPayService implements PayService { ... }
@Component
public class NaverPayService implements PayService { ... }
이런식으로 Kakao와 Naver 두개의 결재 서비스를 구현하고 싶을때, Bean을 2개 이상 등록한다고 가정해보자.
@Service
@RequiredArgsConstructor
public class OrderService {
// 카카오페이가 주입될까, 아니면 네이버페이가 주입될까?
private final PayService payService;
// ...
}
이 경우엔 PayService를 의존성 주입(DI) 하게 될때, Bean이 2개 이상 존재하기 때문에 에러가 발생하게 된다.
이와 같이 2개 이상의 Bean을 사용하고 싶다면, 어떤 방식을 사용해야 될까?
@Primary는 여러 빈 중에서 어떤 빈을 우선적으로 선택할지에 대해 지정해주는 어노테이션이다.
@Component
public class KakaoPayService implements PayService { ... }
@Primary // Primary 어노테이션이 붙어있는 Bean을 우선으로 DI해준다
@Component
public class NaverPayService implements PayService { ... }
}
@Qualifier를 사용하여 특정 Bean을 직접 가져와서 주입할 수 있게하는 어노테이션이다.
@Primary보다 우선순위가 높고, 구체적으로 선택이 가능하다.
@Component("kakaoPay") // "kakaoPay"라는 별명을 붙여줌
public class KakaoPayService implements PayService { ... }
@Component("naverPay")
public class NaverPayService implements PayService { ... }
@Service
public class OrderService {
private final PayService payService;
// @Qualifier("이름")을 사용하여 어떤 Bean을 주입할지에 대해 결정할 수 있다.
public OrderService(@Qualifier("kakaoPay") PayService payService) {
this.payService = payService;
}
}
Bean 스코프는 스프링 빈이 얼마나 오래, 어떤방식으로 존재할지를 정의한다.
Spring에서는 기본적으로 싱글톤 스코프를 사용한다.
@Component
@Scope("singleton") // singleton이 디폴트값
public class SingletoneBean {
// ...
}
위 코드와 같이, 스프링 컨테이너가 시작될 때 딱 한번 생성되고 계속 재사용 된다.
singleton외에도 prototype과 같은 어노테이션이 존재한다.

스프링 빈은 이미지와 같이 생성->의존성 주입->초기화->사용->소멸의 생명주기를 갖는다.
이때, 초기화와 소멸단계 에서는 특정 작업을 수행하는 콜백(Cllback)매서드를 지정할 수 있다.
@Component
public class MoviePlayer {
private List<String> playlist = new ArrayList<>();
// 초기화 콜백: 의존성 주입이 끝난 후 실행
@PostConstruct
public void loadPlaylist() {
System.out.println("--- @PostConstruct 호출 ---");
playlist.add("부산행");
playlist.add("신과함께");
System.out.println("영화 플리 로딩 성공");
}
// 소멸 전 콜백: 빈이 사라지기 직전 실행
@PreDestroy
public void saveProgress() {
System.out.println("--- @PreDestroy 호출 ---");
System.out.println("플레이어를 종료합니다.");
}
}
다음과 같이, @PostConstruct를 사용하여 의존성 주입이 완료된 후 호출할 수 있고, @PreDestroy를 사용하여 빈이 제거되기 직전에 호출할 수 있다.
각각 외부 리소스 가져오기, 초기 설정값 세팅하기 등과 연결 안전하게 종료하기, 임시파일 삭제하기 등의 역할을 한다.