728x90
싱글톤 패턴이든, 스프링 같은 싱글톤 컨테이너를 사용하든,
객체 인스턴스를 하나만 생성해서 공유하는 싱글톤 방식은 여러 클라이언트가 하나의 같은 객체 인스턴스를 공유하기 때문에 싱글톤 객체는 상태를 유지(stateful)하 게 설계하면 안된다.
- ⭕ ⭐무상태(stateless) ⭐ 로 설계해야 한다!!
- ❌ 특정 클라이언트에 의존적인 필드가 있으면 안된다.
- ❌ 특정 클라이언트가 값을 변경할 수 있는 필드가 있으면 안된다. → 스프링 빈의 필드에 공유 값을 설정하면 정말 큰 장애가 발생할 수 있다!!!
- 가급적 읽기만 가능해야 한다.
- 필드 대신 자바에서 공유되지 않는, 지역변수, 파라미터, TreadLocal 등을 사용해야 한다.
상태를 유지할 경우 발생하는 문제점 예시
테스트 코드로 진행하겠다.
StatefulService
package hello.core.singleton;
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;
}
}
StatefulServiceTest
ThreadA가 사용자A 코드를 호출하고 ThreadB가 사용자B 코드를 호출한다 가정하자.
StatefulService 의 price 필드는 공유되는 필드인데, 특정 클라이언트가 값을 변경한다.
package hello.core.singleton;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
public class StatefulServiceTest {
@Test
void statefulServiceSingleton() {
ApplicationContext ac = new
AnnotationConfigApplicationContext(TestConfig.class);
StatefulService statefulService1 = ac.getBean("statefulService",
StatefulService.class);
StatefulService statefulService2 = ac.getBean("statefulService",
StatefulService.class);
//ThreadA: A사용자 10000원 주문
statefulService1.order("userA", 10000);
//ThreadB: B사용자 20000원 주문
statefulService2.order("userB", 20000);
//ThreadA: 사용자A 주문 금액 조회
int price = statefulService1.getPrice(); // 10000원이 아닌 20000원 출력
//ThreadA: 사용자A는 10000원을 기대했지만, 기대와 다르게 20000원 출력
System.out.println("price = " + price);
Assertions.assertThat(statefulService1.getPrice()).isEqualTo(20000);
}
static class TestConfig {
@Bean
public StatefulService statefulService() {
return new StatefulService();
}
}
}
사용자A의 주문금액은 10000원이 되어야 하는데, 20000원이라는 결과가 나왔다.
진짜 공유필드는 조심해야 한다! 스프링 빈은 항상 무상태(stateless)로 설계하자.
그림으로 설명
➕참고 : 무상태 ➕
무상태 프로토콜 스테이스리스(Stateless)
- 서버가 클라이언트의 상태를 보존X
- 장점: 서버 확장성 높음(스케일 아웃)
- 단점: 클라이언트가 추가 데이터 전송
상태 유지(Stateful)
'공부 > Spring' 카테고리의 다른 글
[Spring] 컴포넌트 스캔과 의존관계 자동 주입 시작하기 (1) | 2023.12.18 |
---|---|
[Spring] @Configuration과 싱글톤 (1) | 2023.11.20 |
[Spring] 싱글톤 컨테이너 (0) | 2023.11.20 |
[Spring] 싱글톤 패턴 (0) | 2023.11.16 |
[Spring] 웹 애플리케이션과 싱글톤 (1) | 2023.11.14 |