개발/Spring
(스프링 기본) 15 - 싱글톤 방식의 주의점 (공유필드)
개발하는 인사담당자
2024. 10. 24. 11:21
싱글톤 객체는 여러 클라이언트가 하나의 객체 인스턴스를 공유하기 때문에
객체는 상태를 유지(stateful)하게 설계하면 안되고 무상태(stateless)로 설계해야 한다.
- 특정 클라이언트에 의존적인 필드가 있으면 안됨.
- 특정 클라이언트가 값을 변경하는 필드가 있으면 안됨.
- 가급적 읽기만 가능해야 함
- 필드 대신에 자바에서 공유되지 않는 지역변수, 파라미터, ThreadLocal 등을 사용해야
- 스프링 빈의 필드에 공유값을 설정하면 큰 장애 발생할 수 있음. (주의!!★)
class StateFulServiceTest {
@Test
void statefulServiceSingleton() {
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);
}
static class TestConfig {
@Bean
public StateFulService stateFulService() {
return new StateFulService();
}
}
}
여기서 둘 다 모두 같은 객체를 바라보고 있기 때문에(싱글톤)
order 처리를 한 후 getPrice()를 하면 A 사용자가 주문 금액을 조회해도 20000원이 나온다.
StatefulService 의 price 필드는 공유되는 필드인데, 특정 클라이언트가 값을 변경한다. (문제발생)
public class StateFulService {
// private int price; //상태를 유지하는 필드
public int order(String name, int price) {
System.out.println("name = " + name + "price = " + price);
// this.price = price; //여기가 문제!
return price;
}
@Test
void statefulServiceSingleton() {
ApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
StateFulService stateFulService1 = ac.getBean(StateFulService.class);
StateFulService stateFulService2 = ac.getBean(StateFulService.class);
//ThreadA: A사용자 10000원 주문
int userAPrice = stateFulService1.order("userA", 10000);
//ThreadB: B사용자 20000원 주문
int userBPrice = stateFulService2.order("userB", 20000);
//ThreadA: 사용자A 주문 금액 조회
// int price = stateFulService1.getPrice();
System.out.println("userAPrice = " + userAPrice);
System.out.println("userBPrice = " + userBPrice);
// Assertions.assertThat(stateFulService1.getPrice()).isEqualTo(20000);
}
따라서 이를 int 값으로 반환값으로 아예 돌려주게 만들고
원래 코드에서 직접 값을 출력하게 한다.
출처 : 김영한 스프링 핵심 원리 - 기본편
스프링 핵심 원리 - 기본편 강의 | 김영한 - 인프런
김영한 | 스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., 스프링 핵심 원리를 이해하고, 성장하는 백엔드 개발자가 되어보
www.inflearn.com