
해당 게시글에서는 빈 (Bean)에 대해 좀 더 자세히 알아본다. 이 글에서는 빈의 생명주기 (Lifecycle)와 범위 (Scope)에 대해서 알아볼 것이다.
빈의 생명주기를 공부하기 앞서 생명주기(Lifecycle)에 대한 개념을 먼저 알아야한다. 생명주기(Lifecycle)는 어떤 객체나 시스템이 생성되고, 사용되며, 소멸되는 전 과정을 의미한다. 이는 자연에서 생물의 출생부터 죽음에 이르는 과정을 비유적으로 설명할 때 사용하는 용어이지만, 소프트웨어 공학에서도 동일한 개념이 적용된다. 주요 단계로 나누면 다음과 같다.
| 생명주기의 단계 | 설명 |
|---|---|
| 생성 (Creation) | 객체가 메모리에 할당되고 초기화되는 단계 |
| 사용 (Usage) | 생성된 객체가 실제로 기능을 수행하며, 애플리케이션 내에서 활용되는 단계 |
| 소멸 (Destruction) | 객체가 더 이상 필요하지 않을 때 메모리에서 해제되고 정리되는 단계 |
이러한 생명주기 개념은 객체 지향 프로그래밍(OOP)에서 객체의 관리와 자원 효율성을 높이기 위해 중요하게 다뤄진다.
소프트웨어 개발에서는 생명주기 개념을 다양한 측면에서 적용할 수 있는데, 대표적으로는 객체의 생명주기와 애플리케이션의 생명주기가 있다.
객체 지향 프로그래밍에서 객체의 생명주기는 객체가 생성되어 사용되고 소멸되는 과정을 의미한다.
이 과정은 다음과 같은 단계로 나눌 수 있다.
1) 객체 생성
✍️ 작성
MyClass obj = new MyClass();
new 키워드를 사용하여 객체가 메모리에 할당된다.
2) 객체 초기화
✍️ 작성
public MyClass() { // MyClass의 생성자 코드
// 초기화 작업
}
생성된 객체의 초기 상태를 설정한다.
보통 생성자 (constructor)나 초기화 메서드를 통해 이루어진다.
3) 객체 사용
✍️ 작성
obj.performAction();
4) 객체 소멸
객체가 더 이상 참조되지 않을 때 가비지 컬렉터 (Garbage Collector)에 의해 메모리에서 해제된다.
애플리케이션 전체의 생명주기는 애플리케이션이 시작되고 실행되며 종료되는 과정을 의미한다. 이는 주로 서버 기반 애플리케이션에서 중요하게 다뤄진다.
| 생명주기의 단계 | 설명 |
|---|---|
| 시작 (Startup) | 애플리케이션이 실행되기 시작하며, 필요한 리소스와 설정을 로드 |
| 실행 (Running) | 애플리케이션이 정상적으로 동작하며, 사용자 요청을 처리 |
| 종료 (Shutdown) | 애플리케이션이 종료되기 전에 열린 리소스를 정리하고 필요한 정리 작업을 수행 |
이제 빈의 생명주기의 단계에 대해 알아보겠다. 빈의 생명주기도 지금까지 소개한 객체 및 애플리케이션 생명주기와 유사하다.
| 생명주기의 단계 | 설명 |
|---|---|
| 1. 빈 생성 (Instantiation) | 스프링 컨테이너가 설정 파일이나 어노테이션을 기반으로 빈의 인스턴스를 생성 이 단계에서는 new 키워드를 사용하여 객체가 메모리에 할당됨. |
| 2. 의존성 주입 (Dependency Injection) | 생성된 빈에 필요한 의존성을 주입 예를 들어, 다른 빈을 참조하거나 설정 값을 주입받는 과정 Setter 주입 또는 생성자 주입 방식을 사용 |
| 3. 빈 이름 설정 및 팩토리 정보 제공 | 빈이 BeanNameAware, BeanFactoryAware 등의 인터페이스를 구현하고 있다면, 스프링 컨테이너가 빈의 이름이나 팩토리 정보를 설정 |
| 4. 빈 초기화 전 처리 (BeanPostProcessor) | BeanPostProcessor를 구현한 클래스가 있다면, 초기화 전에 추가적인 처리 가능 예: AOP (Aspect-Oriented Programming)에서 프록시 객체를 생성 |
| 5. 빈 초기화 (Initialization) | 빈이 InitializingBean 인터페이스를 구현했다면 afterPropertiesSet() 메서드를 호출 또는, 설정 파일이나 어노테이션을 통해 지정한 커스텀 초기화 메서드가 실행 이 단계에서 빈은 초기 설정을 마치고 사용 준비가 완료됨. |
| 6. 빈 초기화 후 처리 (BeanPostProcessor) | 초기화 후에 BeanPostProcessor가 추가적인 처리 가능 예: 프록시 설정, 추가 설정 적용 등 |
| 7. 빈 사용 (Usage) | 애플리케이션에서 빈을 실제로 사용 이 단계에서 빈은 비즈니스 로직을 수행 |
| 8. 빈 소멸 (Destruction) | 애플리케이션 종료 시, 스프링 컨테이너가 빈의 소멸을 관리 빈이 DisposableBean 인터페이스를 구현했다면 destroy() 메서드를 호출 또는, 설정 파일이나 어노테이션을 통해 지정한 커스텀 소멸 메서드를 실행 이 단계에서 리소스 해제, 연결 종료 등의 정리 작업 진행 |
✍️ 작성
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
@Component
public class MyBean implements InitializingBean, DisposableBean {
public MyBean() {
System.out.println("빈 생성자 호출");
}
@Override // 5. 빈 초기화 (Initialization) 단계 - 해당 메서드에서 관련 작업 수행
public void afterPropertiesSet() throws Exception {
System.out.println("빈 초기화 메서드 호출");
}
@Override // 8. 빈 소멸 (Destruction) 단계 - 해당 메서드에서 관련 작업 수행
public void destroy() throws Exception {
System.out.println("빈 소멸 메서드 호출");
}
}
위 예제에서 MyBean 클래스는 스프링 빈으로 등록되어 있다.
스프링 컨테이너가 이 빈을 생성하고 초기화하며, 애플리케이션 종료 시 소멸 과정을 거치게 되며, 각 단계에서 콘솔에 메시지가 출력되어 생명주기의 각 단계를 확인할 수 있는 코드이다.
생명주기에 관련된 메서드는 해당 글에서 좀 더 자세히 살펴볼 수 있다.
빈 스코프(Bean Scope)는 스프링 컨테이너가 빈을 생성하고 관리하는 범위와 생명 주기를 정의하는 개념이다. 스코프에 따라 빈의 생성 시점, 사용 범위, 소멸 시점이 달라지며, 애플리케이션의 요구 사항에 맞게 적절한 스코프를 선택할 수 있다.
스프링에서 제공하는 주요 스코프는 Singleton, Prototype, Request, Session, Application, Websocket이 있으며 각각에 대해 살펴보자.
| Singleton 스코프 | |
|---|---|
| 설명 | Singleton 스코프는 스프링 컨테이너당 하나의 빈 인스턴스만 생성 애플리케이션 전체에서 동일한 빈 인스턴스를 공유 스프링의 기본 스코프로, 특별히 스코프를 지정하지 않으면 모든 빈은 싱글톤으로 관리 |
| 사용 예 | 서비스 레이어, DAO(Data Access Object), 공통 유틸리티 클래스 등 상태를 가지지 않고, 애플리케이션 전역에서 공유되는 객체에 주로 사용 |
| 생존 기간 | 애플리케이션 시작 시점부터 종료 시점까지 지속 |
| 생성 시점 | 애플리케이션 컨텍스트가 초기화될 때 (Eager Initialization) |
| 소멸 시점 | 애플리케이션이 종료될 때 소멸 |
✍️ 작성
import org.springframework.stereotype.Service;
@Service // @Scope 어노테이션이 없으므로 기본 스코프인 싱글톤 적용.
public class LoggingService {
public void log(String message) {
System.out.println("Log: " + message);
}
}
LoggingService는 애플리케이션 전체에서 공통으로 사용되는 서비스이다. singleton 스코프로 관리되므로, 애플리케이션 전체에서 하나의 인스턴스만 존재하여 로그 출력 비용을 절감할 수 있다.
| Prototype 스코프 | |
|---|---|
| 설명 | Prototype 스코프는 빈 요청 시마다 새로운 인스턴스를 생성 스프링 컨테이너는 요청할 때마다 빈의 새로운 인스턴스를 반환 Singleton 스코프와 달리, 컨테이너가 빈의 전체 생명주기를 관리하지 않음 빈의 생성과 의존성 주입까지만 관리하고, 이후의 소멸은 개발자가 직접 관리 |
| 사용 예 | 상태를 가지는 객체, 요청마다 새로운 인스턴스가 필요한 경우에 사용 예를 들어, 대화형 세션, 일회성 작업 객체 등에 적합 |
| 생존 기간 | 빈이 요청될 때마다 생성되며, 별도로 소멸되지 않음. 개발자가 직접 관리해야 함. |
| 생성 시점 | 빈이 요청될 때마다 생성 |
| 소멸 시점 | 스프링 컨테이너가 관리하지 않으므로, 개발자가 소멸을 관리 |
✍️ 작성
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("prototype")
public class PrototypeBean {
private int counter = 0;
public void increment() {
counter++;
}
public int getCounter() {
return counter;
}
}
PrototypeBean은 각 요청마다 독립적인 상태를 유지해야 하는 경우에 사용된다. prototype 스코프로 관리되므로, 요청할 때마다 새로운 인스턴스가 생성된다.
| Request 스코프 | |
|---|---|
| 설명 | Request 스코프는 웹 애플리케이션에서 HTTP 요청 하나당 하나의 빈 인스턴스를 생성 각 HTTP 요청마다 독립적인 빈 인스턴스를 제공하며, 요청이 완료되면 빈이 소멸 |
| 사용 예 | HTTP 요청과 밀접하게 연관된 데이터 처리, 요청별로 독립적인 상태가 필요한 경우에 사용 예를 들어, 폼 데이터 처리, 요청별 유효성 검사 등에 적합 |
| 생존 기간 | HTTP 요청이 처리되는 동안 유지 |
| 생성 시점 | HTTP 요청이 들어올 때 생성 |
| 소멸 시점 | HTTP 요청이 완료될 때 소멸 |
✍️ 작성
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.context.annotation.ScopedProxyMode;
@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestData {
private String requestId;
// Getter and Setter
public String getRequestId() {
return requestId;
}
public void setRequestId(String requestId) {
this.requestId = requestId;
}
}
RequestData는 각 HTTP 요청마다 새로운 인스턴스가 생성되며 요청별로 고유한 데이터를 처리하거나 저장할 때 사용된다.
| Session 스코프 | |
|---|---|
| 설명 | Session 스코프는 웹 애플리케이션에서 HTTP 세션 하나당 하나의 빈 인스턴스를 생성 특정 사용자의 세션 동안 빈이 유지되며, 세션이 종료되면 빈도 소멸 |
| 사용 예 | 사용자 세션별 데이터 관리, 로그인 정보 저장, 장바구니 데이터 관리 등에 사용 |
| 생존 기간 | 사용자의 HTTP 세션이 유지되는 동안 지속 |
| 생성 시점 | HTTP 세션이 시작될 때 생성 |
| 소멸 시점 | HTTP 세션이 종료될 때 소멸 |
✍️ 작성
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.context.annotation.ScopedProxyMode;
@Component
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class UserSession {
private String username;
// Getter and Setter
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
UserSession 빈은 각 사용자 세션마다 독립적으로 존재한다. 사용자의 로그인 정보나 세션별 데이터를 관리할 때 유용하다.
| Application 스코프 | |
|---|---|
| 설명 | Application 스코프는 서블릿 컨텍스트 당 하나의 빈 인스턴스를 생성 애플리케이션 전체에서 공유되며, 애플리케이션이 실행되는 동안 유지 |
| 사용 예 | 애플리케이션 전역의 설정 정보 관리, 공통 리소스 관리 등에 사용 |
| 생존 기간 | 애플리케이션이 실행되는 동안 지속 |
| 생성 시점 | 서블릿 컨텍스트가 초기화될 때 생성 |
| 소멸 시점 | 서블릿 컨텍스트가 종료될 때 소멸 |
✍️ 작성
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.context.annotation.ScopedProxyMode;
@Component
@Scope(value = WebApplicationContext.SCOPE_APPLICATION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class ApplicationConfig {
private String configValue;
// Getter and Setter
public String getConfigValue() {
return configValue;
}
public void setConfigValue(String configValue) {
this.configValue = configValue;
}
}
ApplicationConfig 빈은 애플리케이션 전체에서 공유되어야 하는 설정 정보를 관리한다. 서블릿 컨텍스트 동안 유지되므로, 애플리케이션 전역에서 접근할 수 있다.
| Websocket 스코프 | |
|---|---|
| 설명 | WebSocket 스코프는 웹소켓 하나당 하나의 빈 인스턴스를 생성 웹소켓 통신 중 일 때, 빈이 유지되며, 웹소켓 연결이 종료되면 빈도 소멸 |
| 사용 예 | 실시간 통신 데이터 관리, 웹소켓 세션별 데이터 저장 등에 사용 예를 들어, 채팅 애플리케이션, 실시간 알림 시스템 등에 적합 |
| 생존 기간 | 웹소켓 연결이 유지되는 동안 지속 |
| 생성 시점 | 웹소켓 연결이 수립될 때 생성 |
| 소멸 시점 | 웹소켓 연결이 종료될 때 소멸 |
✍️ 작성
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.context.annotation.ScopedProxyMode;
@Component
@Scope(value = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class WebSocketSessionData {
private String sessionId;
// Getter and Setter
public String getSessionId() {
return sessionId;
}
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
}
WebSocketSessionData 빈은 웹소켓 연결 동안 유지되며, 각 웹소켓 세션별 데이터를 관리한다. 실시간 통신 데이터나 웹소켓 세션별 상태를 저장할 때 사용한다.
멋쟁이 사자처럼 강의자료