스프링빈은 항상 무상태로 설계하자

Daniel·2024년 1월 30일
0

Back-End

목록 보기
31/42

무슨말이야?

스프링 빈 클래스는 공유가 될 수 있는 전역 변수를 사용하면 안된다.

스프링 컨테이너는 스프링 빈을 생성할 때 디폴트로 싱글톤 패턴을 사용해 생성합니다.
? singleton(싱글톤) 이란
메모리에 하나의 인스턴스만 존재하도록 생성하는 패턴

따라서 빈을 사용하는 여러 클라이언트가 하나의 인스턴스를 공유하는 결과가 됩니다.
이때, 클라이언트들이 동시에 인스턴스 안 전역변수(상태)에 접근한다면 어떻게 될까요?
상태가 중구난방으로 꼬여버리지 않을까요? -> 그래서 무상태로 설계해야한다는 말입니다.

예시

public class StatefulService {

	private int price; // 상태필드
	
	public void order(String name, int price) {
		System.out.println(" name = " + name + "\n price = " + price);
		this.price = price;
	}
	
	public int getPrice() {
		return price;
	}
	
} // end class

싱글톤 패턴이 하나의 객체만을 생성하고, 공유하여 사용하기 때문에 여러 클라이언트에서 상태를 변경할 수 있습니다.
그렇기 때문에 특정 클라이언트의 price(상태)를 보장하지 않는데요. 아래 코드에서 보시죠

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원 주문
	statefulService1.order("userB", 20000);
	
	//ThreadA: 사용자A 주문 금액 조회
	int price = statefulService1.getPrice();
	
	//ThreadA: 사용자A는 10000원을 기대했지만, 기대와 다르게 20000원 출력
	System.out.println("price = " + price);
}

그래서 어떻게 해야해?

Spring의 권장 방법인 스프링 빈을 무상태로 설계하면 됩니다!

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원 주문
	statefulService1.order("userB", 20000);
	
	//ThreadA: 사용자A 주문 금액 조회
	int price = statefulService1.getPrice();
	
	//ThreadA: 사용자A는 10000원을 기대했지만, 기대와 다르게 20000원 출력
	System.out.println("price = " + price);
}

static class StatelessService {
	public int order(String name, int price) {
		System.out.println(" name = " + name + "\n price = " + price);
		return price;
	}
}

위 코드는 price(상태)를 제거하고 전달받은 price(상태)를 그대로 반환해줌으로써 상태를 관리하는 주체를 클라이언트로 넘기고 있습니다.

profile
응애 나 애기 개발자

0개의 댓글