스프링

싱글톤 방식의 주의점

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된다.

출처 : 인프런 스프링 핵심 원리 - 기본 편  김영한

'스프링' 카테고리의 다른 글

컴포넌트 스캔  (0) 2023.07.17
Configuration과 싱글톤  (0) 2023.07.14
싱글톤 패턴, 싱글톤 컨테이너  (0) 2023.07.11
XML로 스프링 컨테이너 설정 정보 사용하기  (0) 2023.07.10
스프링 빈 조회하기  (0) 2023.07.10