빈 스코프가 뭐에요?
기존에 업로드 한 자바에서 스코프를 떠올려보자. 자바에서 스코프라는 용어는 해당 변수가 생존할 수 있는 생존 범위를 의미 했다.
[Java] Java에서의 스코프(Scope)
배그 하시는 분들 검색 키워드에 이끌려 오셨다면 죄송합니다ㅋㅋJava에서 스코프(Scope) 란 무엇인가?스코프(Scope)란 변수가 접근 가능한 범위를 의미한다.자세한건 아래 코드의 예제를 통해 설명
bdisappointed.tistory.com
스프링에서 빈 스코프란 말 그대로 스프링 빈이 생존할 수 있는 범위를 뜻한다.
스프링은 다음과 같은 다양한 스코프를 지원한다
1. 싱글톤 : 기본 스코프로써, 스프링 컨테이너가 생성될 때 만들어지고 종료될 때 소멸되는 가장 넓은 범위의 스코프이다.
2. 프로토타입 : 프로토타입 빈의 생성 + DI 까지만 관리하고, 이후에는 더는 관리하지 않는 범위의 스코프이다.
3. 웹 관련 스코프 : request, session, application 등 웹 요청 과 관련된 스코프이다
빈 스코프 적용 방법
@Scope 에노테이션을 이용하자
// 자동 등록 빈
@Scope("prototype")
@Component
public class ExBean {}
// 수동 등록 빈
@Scope("prototype")
@Bean
PrototypeBean HelloBean() {
return new HelloBean();
}
프로토 타입 스코프 빈
여태 싱글톤 빈을 신나게 써봤으니, 이번에는 프로토 타입빈을 보겠다
이전에 싱글톤 빈을 생각해보면, 항상 같은 인스턴스의 스프링빈이 어떻게든 반환 되었다. 아래 글 참조

[Spring] Singleton 패턴 : 인스턴스 아나바다 운동
싱글톤 패턴클래스의 인스턴스가 딱 1개만 생성되는 것을 보장하는 디자인 패턴이다. -> 즉 우리는 객체 인스턴스를 2개 이상 생성하지 못하도록 막아야 한다.대표적인 방법으로는 private 생성자
bdisappointed.tistory.com
프로토타입 빈은 싱글톤 빈과 다르게 요청마다 항상 새로운 인스턴스를 생성해서 반환한다는 차이점이 존재한다.


초반에도 언급 했듯이, 프로토타입 빈은 컨테이너가 생성 + DI 이후 반환해주고 더이상 관리하지 않는 빈이다.
여기서 중요한 점이 반환 받은 프로토 타입 빈은 이제 제어권이 클라이언트에게 넘어갔기 때문에, 해당 객체를 정리하는 시점을 스프링이 알지 못한다. 그렇게 때문에 자원을 정리하는 @PreDestory 같은 메서드가 호출 될 수 없다. (하지만 객체를 생성하고 의존 관계를 주입하는 초기화 시점은 알기 때문에 @PostConstruct 는 실행이 가능하다).
프로토 타입 스코프 빈 테스트
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;
import static org.assertj.core.api.Assertions.*;
public class PrototypeTest {
@Test
public 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("PrototypeBean.init");
}
@PreDestroy
public void destroy() {
System.out.println("PrototypeBean.destroy");
}
}
}
스코프를 프로토 타입으로 설정한뒤 실행 결과를 보자

실행 결과를 보면, 프로토타입 빈은 두번 호출했을 때, 서로 완전히 다른 빈이 호출 된 것을 볼 수 있고, @PostConstruct는 실행되지만 @PreDestroy는 실행 되지 않는 것을 볼 수 있다.
만약 해당 스프링 빈을 종료하고 싶다면 어떻게 해야할까?
제어권이 이미 클라이언트에게 있기 때문에 클라이언트가 직접 @PreDestroy 메서드를 실행해야 한다.
다음은 내가 스스로 @PreDestory까지 실행 해보기 위해 작성한 코드이다.
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;
import static org.assertj.core.api.Assertions.*;
public class PrototypeTest {
@Test
public void prototypeBeanFind() {
AnnotationConfigApplicationContext ac =
new AnnotationConfigApplicationContext(PrototypeBean.class);
try (PrototypeBean prototypeBean1 = ac.getBean(PrototypeBean.class);
PrototypeBean prototypeBean2 = ac.getBean(PrototypeBean.class);
){
System.out.println("find prototypeBean1");
System.out.println("find prototypeBean2");
System.out.println("prototypeBean1 = " + prototypeBean1);
System.out.println("prototypeBean2 = " + prototypeBean2);
assertThat(prototypeBean1).isNotSameAs(prototypeBean2);
} catch (Exception e) {
throw new RuntimeException(e);
}finally {
ac.close();
}
}
@Scope("prototype")
static class PrototypeBean implements AutoCloseable {
@PostConstruct
public void init() {
System.out.println("PrototypeBean.init");
}
@Override
@PreDestroy
public void close() throws Exception {
System.out.println("PrototypeBean.destroy");
}
}
}
try - catch - finally 의 변수 스코프 문제를 해결하기 위해 try - with - resources 구문을 사용하여 작성해보았다.
프로토타입 빈 객체에 AutoCloseable을 구현 했고, @PreDestroy를 해당 close() 메서드에 붙이므로 빈이 소멸할 때 반드시 실행 되도록 수정했다.

결과를 보면 빈이 잘 닫히는 것을 확인할 수 있다.
사실 이렇게 안 닫아도 되고..
==수정==
사실 저렇게 쓰면 안된다 !
아무리 AutoCloseable을 구현했어도, @PreDestroy가 실행되지 않기 때문이다.
사실 저렇게 쓴건 그냥 내가 배웠던 자원정리 try - with - resources 를 써보고 싶어서 그런거고..
그냥 모든 비즈니스 로직 이후 close 를 호출하면 된다.
'Spring > Core' 카테고리의 다른 글
| [Spring] 한 컨테이너 안에 같은 타입의 빈이 2개라면? (0) | 2025.06.19 |
|---|---|
| [Spring] DI : 생성자 주입을 선택해야 하는 이유 (0) | 2025.06.19 |
| [Spring] Dependency Injection : 의존 관계 주입의 4가지 방법 (0) | 2025.06.19 |
| [Spring] @ComponentScan , @AutoWired - 자동 Bean 등록 (0) | 2025.06.16 |
| [Spring] Singleton 패턴 : 인스턴스 아나바다 운동 (0) | 2025.06.16 |