빈 스코프(Bean Scope)에 대해 정리하기 전에 빈(Bean)이 무엇인지 알고 넘어가 보자
1. 빈 (Bean)
빈(Bean)은 Spring에서 애플리케이션의 핵심을 구성하고, Spring IoC 컨테이너에 의해 관리되는 객체를 의미한다.
자바에서 우리가 직접 생성하는 일반적인 객체와 달리, Spring은 개발자가 정의한 클래스들을 빈으로 등록하여 자동으로 객체를 인스턴스화, 조립, 관리한다.
즉, 자바에서의 객체 중에서 Spring 컨테이너에 의해 생성되고 관리되는 객체를 빈이라고 한다.
Spring에서는 이 빈을 컨테이너라는 상자 안에 넣고 생성되고 소멸하는 생명 주기 전체를 자동으로 관리해 주기 때문에 개발자는 보다 편리하게 애플리케이션을 개발할 수 있다.
빈은 어떤 편리함을 제공해줄까?
- 객체를 대신 만들어준다.
- 객체 간의 의존성을 자동으로 주입해준다. (서로 연결되어 의존성을 관리해 준다.)
- 빈의 생애 주기 (생성 -> 초기화 -> 소멸)을 관리해 준다.
- 필요한 시점에 의존성 주입을 통해서 자동으로 사용할 수 있게 해 준다.
2. 빈 스코프 (Bean Scope)
Spring은 빈을 자동으로 관리하면서, 빈(bean)의 생명 주기와 사용 범위(Scope)를 설정할 수 있게 한다.
이를 통해 개발자는 빈이 어느 시점에 생성되고, 어느 범위/영역에서 해당 Bean을 사용할 수 있는지 정의할 수 있다.
빈 스코프에는 범위를 정의할 수 있는 다양한 스코프가 있다.
1. 싱글톤 스코프 (Singleton Scope)
싱글톤 스코프는 Spring의 기본 스코프이다.
싱글톤 스코프에 해당되는 bean은 컨테이너에서 단 한 번만 생성이 되며, 애플리케이션 종료 시 컨테이너와 함께 소멸이 된다.
싱글톤 스코프로 Bean이 생성이 되고 의존성 주입이 일어나면, 항상 동일한 객체가 주입된다.
즉, 애플리케이션 전체에서 호출 시 마다 동일한 객체를 참조하기 때문에 동기화와 충돌 문제가 발생할 수 있다.
그래서 상황에 따라 적절한 스코프를 사용해야 한다.
싱글톤 스코프를 사용하기 좋은 예
- 상태가 없는 공유 객체: 멀티스레드 환경에서 동기화 문제가 없기 때문에 새로 생성하지 않아도 되기 때문이다.
- 읽기 전용 상태를 가진 객체: 한 번 초기화된 상태를 변경하지 않는 객체라면 동기화 문제가 없기 때문이다.
- 쓰기 상태가 가능하긴 하지만 사용빈도가 높은 객체: 쓰기 상태가 가능하기 때문에 동기화 비용이 소모되긴 하지만,
많은 객체가 계속 생성이 된다면 효율적인 선택일 수 있다.
싱글톤 스코프를 사용하기 좋지 못한 예
- 요청마다 다른 상태를 가져야 할 경우: 공유된 객체에 사용자별 상태를 저장하면 데이터 충돌이 발생한다.
- 사용자마다 별도의 상태를 가져야할 경우: 객체를 공유하기 때문에 개별 상태 유지가 불가능하다.
- 쓰기 상태가 가능하긴 하지만, 독립적으로 작업하는 객체: 같은 객체를 사용하기 때문에 독립성을 만족시키지 못하기 때문이다.
@Bean
@Scope("singleton") // 기본값이므로 생략 가능
public Single single() {
return new Single();
}
싱글톤 스코프를 사용하면 객체를 요청할 때마다 새로 생성하지 않고 캐시에 저장된 동일한 객체를 반환한다.
// 같은 객체를 반환하는 지 확인하는 코드
private static final String NAME = "ABC";
@Test
public void givenSingletonScope_whenSetName_thenEqualNames() {
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("scopes.xml");
Person personSingletonA = (Person) applicationContext.getBean("personSingleton");
Person personSingletonB = (Person) applicationContext.getBean("personSingleton");
personSingletonA.setName(NAME);
Assert.assertEquals(NAME, personSingletonB.getName());
((AbstractApplicationContext) applicationContext).close();
}
// ------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="personSingleton" class="org.baeldung.scopes.Person" scope="singleton"/>
</beans>
2. 프로토타입 스코프 (Prototype Scope)
프로토타입 스코프를 사용하면 객체를 요청할 때마다 새로운 객체를 생성한다.
즉, 요청할 때마다 새로운 객체를 반환해주고, 같은 클래스를 여러 번 호출해도 전부 다른 객체이다.
프로토타입 스코프를 사용하기 좋은 예
- 요청마다 다른 상태를 가져야할 경우
- 상태가 변하는 객체가 동시에 여러 곳에서 사용되어야 할 경우
- 각 작업마다 객체가 독립적이어야 할 경우
--> 요청할 때마다 새로운 객체를 생성하기 때문에 각기 다른 상태를 유지할 수 있다.
프로토타입 스코프의 단점
- 소멸을 관리해 주지 않는다. 즉, 자원이 있는 경우 명시적으로 닫아줘야 한다.
- 객체를 계속 생성하기 때문에 과도하게 사용하면 메모리 낭비가 된다.
@Bean
@Scope("prototype")
public Prototype prototype() {
return new Prototype();
}
프로토타입 스코프는 생명 주기에서 생성-초기화-의존성 주입까지만 관리하며, 소멸 메서드는 직접 호출해주어야 한다.
// 같은 객체를 반환하는지 확인하는 코드
private static final String NAME = "ABC";
private static final String NAME_OTHER = "DEF";
@Test
public void givenPrototypeScope_whenSetNames_thenDifferentNames() {
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("scopes.xml");
Person personPrototypeA = (Person) applicationContext.getBean("personPrototype");
Person personPrototypeB = (Person) applicationContext.getBean("personPrototype");
personPrototypeA.setName(NAME);
personPrototypeB.setName(NAME_OTHER);
Assert.assertEquals(NAME, personPrototypeA.getName());
Assert.assertEquals(NAME_OTHER, personPrototypeB.getName());
((AbstractApplicationContext) applicationContext).close();
}
// ----------------------------
<bean id="personPrototype" class="org.baeldung.scopes.Person" scope="prototype"/>
3. 웹 스코프
웹 환경에서만 동작하는 특수한 빈 스코프들이다.
1. Request Scope
HTTP 요청마다 하나의 빈을 생성한다.
같은 요청 안에서는 동일한 빈을 참조하지만 새로운 요청이 들어오면 새로운 빈이 생성된다.
요청이 끝나면 빈은 자동으로 소멸한다.
사용예) HTTP 요청마다 다른 데이터를 저장해야 하는 경우
@Bean
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator requestScopedBean() {
return new HelloMessageGenerator();
}
// 간단한 방식
@Bean
@RequestScope
public HelloMessageGenerator requestScopedBean() {
return new HelloMessageGenerator();
}
2.Session Scope
HTTP 세션마다 하나의 빈을 생성한다.
같은 세션 내에서는 동일한 빈을 참조하지만 다른 세션에서는 새로운 빈이 생성된다.
세션이 종료되면 빈은 자동으로 소멸한다.
사용예) 사용자 로그인 상태 유지, 장바구니 데이터 저장
@Bean
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator sessionScopedBean() {
return new HelloMessageGenerator();
}
// 간단한 방식
@Bean
@SessionScope
public HelloMessageGenerator sessionScopedBean() {
return new HelloMessageGenerator();
}
3. Application Scope
웹 애플리케이션이 실행되는 동안 하나의 인스턴스만 존재한다.
*ServletContext(서블릿 콘텍스트) 범위에서 공유되며, 여러 서블릿 및 요청에서 동일한 객체를 참조할 수 있다.
애플리케이션 종료 시 소멸이 된다.
사용예) 앱 전역에서 공유해야 하는 공통 리소스 (설정값, 로깅 객체 등)
* ServletContext: 웹 애플리케이션 전역에서 공유되는 객체로, 웹 애플리케이션의 전역 저장소 역할을 한다.
@Bean
@Scope(value = WebApplicationContext.SCOPE_APPLICATION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator applicationScopedBean() {
return new HelloMessageGenerator();
}
// 간단한 방식
@Bean
@ApplicationScope
public HelloMessageGenerator applicationScopedBean() {
return new HelloMessageGenerator();
}
4. WebSocket Scope
WebSocket 세션 당 하나의 빈을 생성한다.
웹 소켓 연결이 유지되는 동안만 유효하며 소켓 소멸과 함께 소멸된다.
사용예) 웹소켓 기반 앱에서 사용자 연결 상태 유지
@Bean
@Scope(scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator websocketScopedBean() {
return new HelloMessageGenerator();
}
스코프 별 가시성
| 스코프 | 가시성 |
| Singleton ( 싱글톤 ) | 전체 애플리케이션 범위 |
| Prototype ( 프로토타입 ) | 한 번 사용 후, 재사용 안함 |
| Request ( 요청 ) | HTTP 요청 범위 |
| Session ( 세션 ) | 세션 범위 |
| Application ( 애플리케이션 ) | 하나의 웹 애플리케이션 범위에서 공유 가능 |
| Websocket ( 웹 소켓 ) | 웹 소켓 연결 범위 |
핵심 요약
- 스코프 설정은 객체의 목적과 사용 상황에 맞게 신중하게 결정해야 한다.
- 스코프는 무분별하게 사용할 경우 동시성 문제, 메모리 누수 등의 문제를 일으키기 때문에 주의하여 사용해야 한다.
- 싱글톤 스코프가 default이며, 대부분의 경우 사용한다.
- 스코프는 유지보수를 고려한 명확한 설계 원칙이 필요하다.
'Spring' 카테고리의 다른 글
| [Spring] AOP & Proxy 란? (3) | 2025.08.01 |
|---|---|
| [Spring] 트랜잭션 전파(Propagation) 정리 (3) | 2025.07.12 |
| [Spring] JDBC Template 정리 (0) | 2025.05.31 |
| [Spring] MVC 정리 (0) | 2025.04.12 |
| [Spring] IoC / DI 정리 (0) | 2025.03.22 |