객체 인스턴스를 하나만 만들어서 공유하여 사용하는 싱글톤 방식의 객체는 상태를 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 |