본 프로젝트 자료는 김영한님의 스프링 핵심 원리 - 기본편 참고 제작됐음을 알립니다.
싱글톤 컨테이너란 클래스의 인스턴스가 Java JVM 내의 단 하나만 존재하는 것을 뜻 한다. 그래서 객체 인스턴스가 2개 이상 생성하는걸 막아야 하는데, 그 부분을 private 생성자를 사용해서 강제로 단일로 사용하게 막을 수 있다.
관련 코드
public class SingletonService {
private static final SingletonService instance = new SingletonService();
public static SingletonService getInstance() {
return instance;
}
private SingletonService() {
}
public void logic() {
System.out.println("싱클톤 객체 로직 호출");
}
}
하지만 이 방식으로 작성할 경우 많은 불편함과 문제점이 생긴다.
스프링 컨테이너는 위와 같은 기존의 싱글톤 패턴의 문제점을 해결해준다.
전에 학습한 스프링 빈이 바로 싱글톤으로 관리되는 빈이라는 점을 참고.
관련 코드
@Test
@DisplayName("스프링 컨테이너와 싱글톤")
void singletonContainer() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService1 = ac.getBean("memberService", MemberService.class);
MemberService memberService2 = ac.getBean("memberService", MemberService.class);
System.out.println("memberService1 = " + memberService1);
System.out.println("memberService2 = " + memberService2);
assertThat(memberService1).isSameAs(memberService2);
}
싱글톤 컨테이너 적용 후 모습
위 예제 코드 덕에 사용자의 요청이 올 때 마다 객체를 생성하는게 아니라, 이미 만들어진 객체를 공유함으로서 효울이 올라간 모습을 볼 수 있다.
싱글톤 방식 자체가 하나의 객체 인스턴스를 생성해 많은 사용자들이 공유 및 제사용으로 트레픽을 줄이는 목적을 사용하지만 생성할 때 와 설계할 때 용도를 잘 파악하고 거기에 맞춰서 설계해야한다.
관련 이유는 만약 결제 관련된 프로그램이 싱글톤 객체 상태를 stateful(유지상태)하게 설계된다면 큰일(?)이 발생한다고 한다.
관련 문제점 예시) 설계 코드
public class StatefulService {
private int price; // 상태를 유지하는 필드
public void order(String name, int price) {
System.out.println("name = " + name + " price = " + price);
this.price = price; // 여기가 문제!
}
public int getPrice() {
return price;
}
}
주문 정보 생성 프로그램 코드
class StatefulServiceTest {
@Test
void statefulServiceSingletin() {
ApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
StatefulService statefulService1 = ac.getBean(StatefulService.class);
StatefulService statefulService2 = ac.getBean(StatefulService.class);
// ThreadA: A사용자 10000원 주문
statefulService1.order("userA", 10000);
// ThreadB: B사용자 20000원 주문
statefulService2.order("userB", 20000);
// ThreadA: A사용자 주문 금액 조회
int price = statefulService1.getPrice();
System.out.println("price = " + price);
Assertions.assertThat(statefulService1.getPrice()).isEqualTo(20000);
}
static class TestConfig {
@Bean
public StatefulService statefulService() {
return new StatefulService();
}
}
}
위 코드 작성대로 실행한다면 아래와 같은 문제점이 생긴다.
Spring 2일차