카테고리 없음
9월 8일 금요일 TIL 회고록
tft4rollz
2023. 9. 9. 02:07
프로토타입 스코프 - 싱글톤 빈과 함께 사용시 문제점
빈 스코프란?
스프링 빈(Bean) : 스프링 컨테이너에서 관리하는 자바 객체
스코프(Scope) : 존재할 수 있는 범위
즉, 빈 스코프는 스프링 빈이 존재할 수 있는 범위를 뜻한다. 지금까지는 기본적으로 스프링 컨테이너에서 스프링 빈이 싱글톤 스코프로 생성되었기 때문에, 스프링 컨테이너와 생명주기를 같이 했기에 신경 쓸 필요가 없었다.
하지만, 빈 스코프를 어떻게 설정하느냐에 따라 스프링 빈의 생성과 소멸을 클라이언트에서 관리해줘야하는 경우도 생길 수 있고, 다양한 요구사항에 맞는 스코프를 지정해 사용할 수 있다.
웹 관련 스코프
- Request : 웹 요청이 들어오고 나갈때까지 유지되는 스코프
- Session : 웹 세션이 생성되고 종료될 때까지 유지되는 스코프
- Application : 웹의 서블릿 컨텍스트와 같은 범위로 유지되는 스코프
빈 스코프 사용 방법
- 컴포넌트 스캔 자동 등록
@Scope("prototype")
@Component
public class PrototypeBean {
}
- 수동 등록
@Scope("prototype")
@Bean
PrototypeBean HelloBean() {
return new HelloBean();
}
프로토 타입 스코프
기존의 스프링 컨테이너에 등록된 스프링 빈은 싱글톤 스코프라고 말을 하였으며, 그렇기에 스프링 컨테이너는 항상 같은 인스턴스의 스프링 빈을 반환한다.
- 싱글톤 스코프의 스프링 빈 요청
- 싱글톤 스코프의 빈을 요청하면 모두 동일한 스프링 빈을 반환한다.
- 프로토타입 스코프의 스프링 빈 요청
- 클라이언트에서 프로토타입 스코프의 스프링 빈을 스프링 컨테이너에 요청
- 스프링 컨테이너는 이 시점에서 프로토타입 빈을 생성하고, 의존관계 주입(DI)
- 생성한 프로토타입 빈을 클라이언트에 반환
여기서 프로토타입은 싱글톤 타입의 스프링 빈과는 다르게 빈 생성, 의존관계 주입, 초기화까지만 진행한다. 그렇기에 그 이후 스프링 빈을 클라이언트에 반환한 이후로는 관리하지 않기에 소멸 메서드같은 것은 모두 클라이언트에서 자체적으로 관리해야한다.
Singleton 스코프 테스트
package hello.core.scope;
import static org.assertj.core.api.Assertions.*;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Scope;
public class SingletonTest {
@Test
void singletonBeanFind() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(
singletonBean.class);
singletonBean singletonBean1 = ac.getBean(singletonBean.class);
singletonBean singletonBean2 = ac.getBean(singletonBean.class);
System.out.println(singletonBean1);
System.out.println(singletonBean2);
assertThat(singletonBean1).isSameAs(singletonBean2);
ac.close();
}
@Scope("singleton")
static class singletonBean {
@PostConstruct
public void init() {
System.out.println("singletonBean.init");
}
@PreDestroy
public void destroy() {
System.out.println("singletonBean.destroy");
}
}
}
테스트 실행 결과
- 싱글톤 스코프의 스프링 빈은 여러번 호출해도 모두 같은 인스턴스 참조 주소값을 가진다.
- 스프링 컨테이너 종료시 소멸 메서드도 자동으로 실행된다.
Prototype 스코프 빈 테스트
package hello.core.scope;
import static org.assertj.core.api.Assertions.*;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Scope;
public class PrototypeTest {
@Test
void prototypeBeanFind() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(
PrototypeBean.class);
System.out.println("find prototypeBean1");
PrototypeBean prototypeBean1 = ac.getBean(PrototypeBean.class);
System.out.println("find prototypeBean2");
PrototypeBean prototypeBean2 = ac.getBean(PrototypeBean.class);
System.out.println("prototypeBean1 = " + prototypeBean1);
System.out.println("prototypeBean2 = " + prototypeBean2);
assertThat(prototypeBean1).isNotSameAs(prototypeBean2);
ac.close();
}
@Scope("prototype")
static class PrototypeBean {
@PostConstruct
public void init() {
System.out.println("singletonBean.init");
}
@PreDestroy
public void destroy() {
System.out.println("singletonBean.destroy");
}
}
}
테스트 실행 결과
- 프로토타입 빈 2개가 참조하는 인스턴스 참조 주소값이 다르다.
- 스프링 컨테이너 종료시 소멸 메서드가 실행되지 않았다.
정리
- 싱글톤은 스프링 컨테이너와 생명주기를 같이하지만, 프로토타입 스프링 빈은 생명주기를 달리한다.
- 싱글톤 스프링 빈은 매번 스프링 컨테이너에서 동일한 인스턴스를 반환하지만, 프로토타입 스프링 빈은 스프링 컨테이너에 요청할 때마다 새로운 스프링 빈을 의존관계까지 주입 및 초기화 진행 후 반환한다.
- 프로토타입 스프링 빈은 소멸 메서드가 호출되지 않는다.
- 클라이언트가 프로토타입 스프링 빈을 직접 관리해야 한다. (소멸 메서드도 직접 호출해야한다.)
출처 : 김영한님 스프링 강의, 블로그 참고