스프링
싱글톤 방식의 주의점
salmon16
2023. 7. 11. 21:34
객체 인스턴스를 하나만 만들어서 공유하여 사용하는 싱글톤 방식의 객체는 상태를 stateful 하게 설계하면 안 된다.
stateless 하게 설계해야 한다.
즉 특정 클라이언트가 값을 변경할 수 있는 필드가 있으면 안 되고,
특정 클라이언트에 의존적인 필드가 있으면 안 된다.
필드 대신에 자바에서 공유되지 않는 지역변수, 파라미터, ThreadLocal 등을 사용해야 한다.
문제점 예시를 보자
public class StatefulService {
private int price; // 상태를 유지하는 필드, 공유되는 필드
public void order(String name, int price) {
System.out.println("name = " + name + " privce = " +price);
this.price = price; //여기가 문제, 특정 클라이언트가 값을 변경할 수 있다.
}
public int getPrice() {
return price;
}
}
StatefulService statefulService1 = ac.getBean(StatefulService.class);
StatefulService statefulService2 = ac.getBean(StatefulService.class);
//ThreadA : A사용자가 10000원 주문
statefulService1.order("userA", 10000);
//ThreadB "B사용자가 20000원 주문
statefulService2.order("userA", 20000);
//ThreadA: 사용자 A가 주문금액을 조회
int price = statefulService1.getPrice();
System.out.println("price = " + price);
int price값을 우리는 10000이 나오길 원했는데 20000이 나오게 된다.
이 문제는 공유필드를 제거하고 생성자 함수의 return 타입을 바꾸어 주면 해결된다.
getPrice() 함수도 제거한다.
public int order(String name, int price) {
System.out.println("name = " + name + " privce = " +price);
return price
}
statelessService statelessService1 = ac.getBean(statelessService.class);
statelessService statelessService2 = ac.getBean(statelessService.class);
//ThreadA : A사용자가 10000원 주문
int priceA = statelessService1.order("userA", 10000);
//ThreadB "B사용자가 20000원 주문
int priceB = statelessService2.order("userA", 20000);
//ThreadA: 사용자 A가 주문금액을 조회
System.out.println("priceA = " + priceA);
이렇게 코드를 작성하면 priceA에 10000이 할당된다.
10000이 print된다.
출처 : 인프런 스프링 핵심 원리 - 기본 편 김영한