8. @Scope를 사용하여 싱글톤, 프로토타입 정하기
기본적으로 Spring 컨테이너는 인스턴스를 싱글톤으로 저장하고 있다.
하지만 @Scope를 사용해서 프로토 타입으로 인스턴스를 저장하면 호출시 다른 인스턴스가 호출된다.
@Component
class NormalClass {
}
@Scope(value=ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
class PrototypeClass {
}
@Configuration
@ComponentScan
public class BeanScopesLauncherApplication {
public static void main(String[] args) {
try (var context =
new AnnotationConfigApplicationContext
(BeanScopesLauncherApplication.class)) {
System.out.println(context.getBean(NormalClass.class));
System.out.println(context.getBean(NormalClass.class));
System.out.println(context.getBean(NormalClass.class));
System.out.println(context.getBean(NormalClass.class));
System.out.println(context.getBean(NormalClass.class));
System.out.println(context.getBean(NormalClass.class));
System.out.println(context.getBean(PrototypeClass.class));
System.out.println(context.getBean(PrototypeClass.class));
System.out.println(context.getBean(PrototypeClass.class));
System.out.println(context.getBean(PrototypeClass.class));
}
}
}
결과
com.in28minutes.learnspringframework.examples.d1.NormalClass@478db956
com.in28minutes.learnspringframework.examples.d1.NormalClass@478db956
com.in28minutes.learnspringframework.examples.d1.NormalClass@478db956
com.in28minutes.learnspringframework.examples.d1.NormalClass@478db956
com.in28minutes.learnspringframework.examples.d1.NormalClass@478db956
com.in28minutes.learnspringframework.examples.d1.NormalClass@478db956
com.in28minutes.learnspringframework.examples.d1.PrototypeClass@6ca18a14
com.in28minutes.learnspringframework.examples.d1.PrototypeClass@c667f46
com.in28minutes.learnspringframework.examples.d1.PrototypeClass@51bd8b5c
com.in28minutes.learnspringframework.examples.d1.PrototypeClass@7b50df34
위의 노말클래스는 싱글톤으로 매번 같은 인스턴스가 호출되지만
프로토클래스는 다른 인스턴스가 호출된다
구분 | 싱글톤(Singleton) | 프로토타입(Prototype) |
설명 | 스프링 컨테이너에서 빈을 한 번만 생성하여 공유 | 요청할 때마다 새로운 인스턴스를 생성 |
빈 생성 횟수 | 한 번만 생성 (애플리케이션 전체에서 하나의 인스턴스) | 요청할 때마다 새로운 빈이 생성됨 |
라이프사이클 | 스프링 컨테이너가 시작될 때 생성되고, 종료될 때 소멸 | 빈이 호출될 때마다 생성되고, 컨테이너가 관리하지 않음 |
상황에 적합 | 상태를 공유하는 객체나 재사용이 필요한 객체에 적합 | 상태를 공유하지 않는 객체나 매번 새로운 인스턴스가 필요한 경우 |
장점 | 메모리 절약, 성능 최적화, 빈 관리 용이 | 상태 유지 없이 독립적인 작업을 처리하는 데 유리 |
단점 | 상태가 공유되므로, 여러 스레드에서 동시 접근 시 주의 필요 | 매번 새로운 객체가 생성되므로 메모리 및 성능에 부하 가능 |
예시 사용 | @Scope("singleton") (기본 스코프) | @Scope("prototype") |
의존성 주입 시 동작 | 주입 시점에 하나의 인스턴스가 생성되고 재사용됨 | 주입할 때마다 새로운 인스턴스를 주입 |
스프링 관리 여부 | 스프링이 라이프사이클을 관리 (생성과 소멸) | 생성 후 스프링이 관리하지 않음 (사용자가 수동으로 관리해야 함) |
사용 예시 | 서비스, 리포지토리 등 상태가 공유되어도 괜찮은 객체 | 사용자 세션, 요청별로 상태가 달라지는 객체 |
-> 거의 대부분은 싱글톤 방식을 사용
그렇다면 언제 프로토 타입을 사용해야 할까?
-> 여러 유저의 정보를 저장하거나 StateFul한 처리를 해야할 때 사용할 수 있다.
-> 각 요청마다 독립적인 상태를 유지해야할 때 프로토 타입 스코프를 사용한다.
- 프로토타입 스코프는 빈을 요청할 때마다 새로운 객체를 생성합니다.
즉, 프로토타입 빈을 사용하면 각 요청마다 독립적인 객체 인스턴스가 생성되므로, 유저별로 서로 다른 상태를 저장하고 관리할 수 있습니다. - 예를 들어, 유저가 로그인하고 나서 세션 동안 특정 정보를 저장하거나 요청마다 다른 유저 정보가 관리되어야 한다면:
- 프로토타입 빈을 사용하여 유저마다 개별 상태를 가진 객체가 생성됩니다.
- 이 경우 한 유저의 정보가 다른 유저와 섞이는 문제가 발생하지 않습니다.