스프링에서 빈은 기본적으로 싱글톤으로 관리되지만, 필요에 따라 다양한 생명주기를 가진 스코프를 지정할 수 있다. 이 글에서는 빈의 스코프 개념을 정리하고, 특히 싱글톤과 프로토타입 스코프의 차이점과 사용 시 주의사항을 설명한다.
1. 빈 스코프란?
스코프는 빈이 생성되고 존재할 수 있는 범위를 뜻한다. 스프링 컨테이너는 기본적으로 모든 빈을 싱글톤으로 관리하지만, 필요에 따라 스코프를 변경할 수 있다.
스프링에서 지원하는 스코프는 다음과 같다.
| singleton | (기본값) 컨테이너 시작~종료까지 하나의 인스턴스 유지 |
| prototype | 요청 시마다 새 인스턴스 생성 |
| request | 하나의 HTTP 요청 범위 동안 유지 (웹 전용) |
| session | 하나의 HTTP 세션 동안 유지 (웹 전용) |
| application | 서블릿 컨텍스트와 동일한 범위 (웹 전용) |
2. 싱글톤 스코프
싱글톤 스코프는 가장 기본적인 스코프로, 스프링 컨테이너 초기화 시점에 빈을 생성하고, 컨테이너가 종료될 때까지 해당 객체를 계속 재사용한다.

예시 코드로 좀 더 알아보자
@Scope("singleton")
@Component
public class SingletonBean {
@PostConstruct
public void init() { System.out.println("초기화"); }
@PreDestroy
public void destroy() { System.out.println("소멸"); }
}
- @PostConstruct → 컨테이너 초기화 시 호출
- @PreDestroy → 컨테이너 종료 시 호출
3. 프로토타입 스코프
프로토타입 스코프는 빈을 요청할 때마다 새로운 인스턴스를 생성한다. 초기화 메서드는 호출되지만, 종료 메서드는 스프링이 호출하지 않는다.
이를 사용하는 이유는 어떤 객체가 내부적으로 상태(예: 카운터, 임시 데이터 등)를 가지는데,
이 상태가 공유되면 안 되고, 매번 새롭게 초기화된 객체가 필요할 때 사용한다.
또한 단기간 사용하는 객체를 스프링이 관리해주되, 생명주기를 직접 관리하고 싶을 때 사용한다.


여기서 핵심은 스프링 컨테이너는 프로토타입 빈을 생성하고. 의존관계 주입, 초기화까지만처리한다는 것이다. 클라이언트에 빈을 반환하고, 이후 스프링 컨테이너는 생성된 프로토타입 빈을 관리하지 않는다. 프로토타입 빈을 관리할 책임은 프로토타입 빈을 받은 클라이언트에 있다. 그래서 @PreDestory같은 종료 메서드가 호출되지 않는다
코드로 알아보자
@Scope("prototype")
@Component
public class PrototypeBean {
@PostConstruct
public void init() { System.out.println("초기화"); }
@PreDestroy
public void destroy() { System.out.println("소멸"); }
}
- @PostConstruct는 정상적으로 동작
- @PreDestroy는 호출되지 않음 → 클라이언트가 직접 종료 처리 필요
4. 싱글톤 빈과 프로토타입 빈 함께 사용할 때의 문제점
싱글톤 빈 내부에 프로토타입 빈을 주입하면, 프로토타입 빈이 한 번만 생성되어 재사용되는 문제가 발생한다.
@Component
public class SingletonClient {
private final PrototypeBean prototypeBean;
public SingletonClient(PrototypeBean prototypeBean) {
this.prototypeBean = prototypeBean;
}
public int logic() {
prototypeBean.addCount();
return prototypeBean.getCount();
}
}
- 생성자 주입으로 프로토타입 빈이 주입될 경우, 생성 시점에 한 번만 주입된다.
- 이후에는 계속 같은 인스턴스를 사용하게 되어, 프로토타입의 의도가 무력화된다.
5. Provider로 문제 해결
매번 새로운 프로토타입 빈을 사용하고 싶다면, javax.inject.Provider 또는 ObjectProvider를 사용해야 한다.
@Component
public class SingletonClient {
@Autowired
private Provider<PrototypeBean> provider;
public int logic() {
PrototypeBean prototypeBean = provider.get();
prototypeBean.addCount();
return prototypeBean.getCount();
}
}
- provider.get() 호출 시마다 새로운 인스턴스를 요청할 수 있다.
- ObjectProvider는 스프링 전용이며, 좀 더 유연한 기능 제공
6. 웹 스코프
웹 애플리케이션에서는 사용자마다 다른 데이터를 다뤄야 할 때가 많다. 예를 들어 로그인 정보, 장바구니 상태 등은 각 사용자마다 독립적으로 유지되어야 하므로, 빈의 범위를 HTTP 요청 단위 또는 세션 단위로 구분해서 관리할 필요가 있다.
이런 상황에서 사용하는 것이 바로 웹 스코프(Web Scope)다. 웹 환경에서 빈의 생명주기를 요청, 세션, 어플리케이션 범위에 맞춰 유연하게 관리할 수 있도록 지원한다.
스프링이 제공하는 주요 웹 스코프는 다음과 같다.
request 스코프
- 하나의 HTTP 요청이 들어올 때마다 새로운 빈이 생성된다.
- 요청이 끝나면 해당 빈은 자동으로 소멸된다.
- 주로 컨트롤러나 필터 등 요청에 따라 데이터를 생성하고 처리해야 하는 상황에 사용한다.
예시
요청 로그를 수집하는 빈은 request 스코프로 설정하면 요청마다 새로운 인스턴스를 사용할 수 있다. 이때 proxyMode 옵션을 함께 설정해야 싱글톤 빈에 안전하게 주입할 수 있다.
@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyLogger {
private String uuid = UUID.randomUUID().toString();
}
session 스코프
- 하나의 HTTP 세션 범위에서 빈을 유지한다.
- 세션이 만료되거나 로그아웃할 때 빈도 함께 제거된다.
- 로그인 사용자 정보를 저장하거나, 사용자별 설정을 보관할 때 유용하다.
application 스코프
- 웹 애플리케이션 전체에서 단 하나만 생성되고 유지되는 스코프이다.
- 서블릿 컨텍스트(ServletContext) 범위와 같다.
- 공통 설정 값, 초기 데이터 등을 저장할 때 사용한다.
이처럼 웹 환경에서는 요청 단위, 세션 단위, 애플리케이션 단위로 빈의 생명주기를 나누어야 할 경우가 많다. 웹 스코프를 적절히 활용하면, 상태 관리가 필요한 상황에서도 빈의 생명주기를 명확히 하고, 애플리케이션의 안정성과 구조를 더욱 견고하게 만들 수 있다.
마무리하며
스프링의 빈 스코프를 올바르게 사용하면 객체의 생명주기를 효율적으로 관리할 수 있다. 특히 프로토타입 빈이나 웹 스코프 빈을 사용할 때는 의도와 다르게 동작하지 않도록 주의해야 하며, 필요에 따라 Provider나 프록시 방식을 적절히 선택하는 것이 중요하다.
'스프링' 카테고리의 다른 글
| [스프링] JPA 기본 매핑 어노테이션 (4) | 2025.07.24 |
|---|---|
| [스프링] JPA란? (1) | 2025.07.24 |
| [스프링] 빈 생명주기 콜백 (3) | 2025.07.24 |
| [스프링] 의존관계 자동 주입에 대하여 (0) | 2025.06.26 |
| [스프링] 싱글톤과 스프링 컨테이너에 대하여 (3) | 2025.06.26 |
