빈 생명주기와 스코프
빈 생명주기란
- 스프링 빈은 객체를 생성한 뒤 바로 사용되는 것이 아니라, 필요한 준비를 마친 뒤 사용되다가 종료 시점에 정리되는데, 이 흐름을 빈 생명주기라고 함
- 스프링 컨테이너가 빈을 생성하고 의존관계를 주입한 뒤, 초기화 작업을 수행하며, 컨테이너가 종료될 때 소멸 작업까지 처리함

빈 생명주기 단계는 다음과 같음
- 스프링 컨테이너가 빈을 생성
- 의존관계 주입
- 초기화 작업을 수행
- 빈을 사용
- 컨테이너 종료 시 소멸 작업을 수행 (singleton 빈인 경우)
-
초기화 단계에서는 빈을 사용하기 전에 필요한 준비 작업을 수행함
- 외부 API 클라이언트의 설정, 메시지 큐 연결 준비, 커넥션 풀 같은 자원 초기화
-
소멸 단계에서는 컨테이너가 종료될 때 사용하던 자원을 정리함
- 메시지 큐 연결 닫기, 외부 연결 해제, 사용 중이던 자원 반납
생명주기 콜백
-
생명주기 콜백: 빈의 특정 생명주기 시점에 스프링이 호출하는 메서드
-
생명주기 콜백을 통해 빈이 생성된 뒤 초기화 작업을 실행하거나, 소멸되기 직전에 정리 작업을 실행
-
실무에서는 보통
@PostConstruct와@PreDestroy를 많이 사용함 -
InitializingBean과DisposableBean도 사용할 수 있지만, 빈 클래스가 인터페이스를 직접 구현해야 하므로 코드가 스프링에 의존하게 됨
@PostConstruct와 @PreDestroy
@PostConstruct: 빈 생성과 의존 관계 주입이 끝난 뒤 호출할 메서드에 붙임@PreDestroy: 컨테이너가 빈을 제거하기 전에 호출할 메서드에 붙임
@Component
public class NetworkClient {
@PostConstruct
public void init() {
System.out.println("초기화 작업 수행");
}
@PreDestroy
public void close() {
System.out.println("연결 종료");
}
}
InitializingBean과 DisposableBean
InitializingBean: 초기화 시afterPropertiesSet()메서드 호출DisposableBean: 소멸 시destroy()메서드 호출
@Component
public class NetworkClient implements InitializingBean, DisposableBean {
@Override
public void afterPropertiesSet() {
System.out.println("초기화 작업 수행");
}
@Override
public void destroy() {
System.out.println("연결 종료");
}
}
- 위와 같이 오버라이드하여 사용하면 됨
빈 스코프
- 빈 스코프: 스프링 컨테이너가 빈을 어떤 범위와 생명주기로 관리할지를 결정하는 개념
- 인스턴스를 몇 개 만들지, 어디까지 공유할지, 언제까지 유지할지 등등
- 스코프에 따라 빈의 생성 시점, 공유 범위, 생명주기가 달라짐
싱글톤
-
싱글톤 스코프: 스프링 컨테이너당 하나의 빈 인스턴스만 생성하는 스코프
-
같은 빈을 주입받아도 같은 객체가 사용됨
-
스프링의 기본 스코프
-
즉, 별도로 스코프를 지정하지 않으면 기본적으로 빈은 싱글톤으로 등록
-
서비스, 레포지토리, 컨트롤러처럼 애플리케이션 전반에서 공통으로 사용하는 객체는 보통 싱글톤으로 관리함
-
다만 여러 요청이 같은 객체를 사용할 수 있으므로, 요청별로 달라지는 상태를 필드에 저장하면 안 됨
-
따라서 싱글톤 빈은 보통 요청마다 달라지는 값을 객체의 필드에 저장하지 않음
프로토타입
-
프로토타입 스코프: 컨테이너에 빈을 요청할 때마다 새로운 빈 인스턴스를 생성하는 스코프
-
싱글톤과 달리 컨테이너가 하나의 인스턴스를 계속 재사용하지 않음
-
같은 빈을 여러 번 조회하면 매번 새로운 객체가 반환됨
-
매번 독립된 인스턴스가 필요한 객체에 적용할 수 있음
-
다만 프로토타입 빈은 생성과 의존 관계 주입, 초기화까지만 스프링 컨테이너가 처리함
-
이후에는 컨테이너가 해당 인스턴스를 계속 추적하지 않으므로, 소멸 콜백은 기본적으로 호출되지 않음
웹 스코프
-
웹 스코프: 웹 환경에서만 사용할 수 있는 스코프
-
대표적으로
request,session,application,websocket스코프가 있음 -
request: 하나의 HTTP 요청 동안만 빈을 유지
- 요청이 시작될 때 생성되고 요청이 끝나면 소멸
- 요청별로 독립적인 데이터를 담아야 하는 객체에 사용
-
session: 하나의 HTTP 세션 동안 빈을 유지
- 같은 세션에서는 요청이 달라도 같은 인스턴스를 사용하고, 세션이 종료되면 소멸
- 세션 단위로 데이터를 유지해야 하는 경우 사용
-
application: 하나의
ServletContext동안 빈을 유지- 같은 웹 애플리케이션 안에서 하나의 인스턴스를 공유함
- singleton과 비슷하지만, singleton은 스프링 컨테이너 안에서 하나의 인스턴스를 공유하고, application 스코프는 하나의
ServletContext안에서 하나의 인스턴스를 공유함
-
websocket: WebSocket 세션 하나의 생명주기 동안 빈을 유지
- WebSocket 연결 단위로 인스턴스를 유지함
- STOMP 기반 WebSocket 애플리케이션에서 사용할 수 있음
@Bean
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public RequestTracker requestTracker() {
return new RequestTracker();
}
- 웹 스코프 빈을 등록할 때는
@Scope의value에 스코프 이름을 지정 - request나 session 스코프 빈을 singleton 빈에 주입해야 한다면 scoped proxy를 함께 설정함
- singleton 빈은 여러 요청이 공유할 수 있는 반면 request 빈은 요청마다 별도의 객체가 사용됨
- 만약 singleton 빈에 request 빈을 직접 주입하면, singleton 빈이 특정 request 빈을 계속 들고 있게 되거나, singleton 빈 생성 시점에 HTTP 요청이 없어 request 빈을 만들 수 없게 됨
- 따라서 scoped proxy를 사용하여 singleton 빈에 실제 request 빈이 아니라 프록시를 사용하여, 메서드 호출 시점에 HTTP 요청에 맞는 실제 request 빈을 찾아 호출을 넘김
scoped proxy: 생명주기가 다른 빈을 singleton 빈에서 사용할 수 있도록 중간에서 호출을 대신 처리하는 프록시 객체
댓글