[Spring 핵심원리 기본편] 웹 애플리케이션과 싱글톤2
by mini_min싱글톤 방식의 주의점
싱글톤 객체는 상태를 유지하게 설계하면 안된다. 무상태로 설계해야한다!
- 특정 클라이언트에 의존적인 필드가 있으면 안된다.
- 특정 클라이언트가 값을 변경할 수 있는 필드가 있으면 안된다.
- 가급적 읽기만 가능해야한다.
- 필드 대신에 자바에서 공유되지 않는, 지역변수, 파라미터, ThreadLocal 등을 사용해야한다.
package hello.core.singleton;
public class StatefulService {
private int price; //상태를 유지하는 필드
public void order(String name, int price){
System.out.println("name = " + name + " price = "+ price);
this.price = price; // 여기가 문제
}
public int getPrice(){
return price;
}
}
price 필드는 공유되는 필드로, 특정 클라이언트가 값을 변경하고 있다. 그래서 마지막 2만원이라는 결과가 나온다.
공유 필드는 특히나 더 조심! 주의해야한다. 스프링 빈은 항상 무상태로 설계하자.
package hello.core.singleton;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import static org.junit.jupiter.api.Assertions.*;
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 사용자가 만원 주문 / B가 2만원 주문
statefulService1.order("userA", 10000);
statefulService1.order("userB", 20000);
//ThreadA: 사용자A가 주문 금액 조회
int price = statefulService1.getPrice();
//의도는 1만원이 나와야하는데, 2만원이 나온다.
//같은 인스턴스를 쓰기 때문에 마지막 2만원이 나올 수 밖에 ...
System.out.printf("price = " + price);
Assertions.assertThat(statefulService1.getPrice()).isEqualTo(20000);
}
static class TestConfig{
@Bean
public StatefulService statefulService(){
return new StatefulService();
}
}
}
@Configuration 과 싱글톤
스프링 컨테이너는 싱글톤 레지스트리다. 따라서 스프링 빈이 싱글톤이 되도록 유지해야한다.
* 비밀은 @Configuration !
스프링이 CGLIB 라는 바이트코드 조작 라이브러리를 사용해서 AppConfig 클래스를 상속받은 임의의 다른 클래스를 만들고, 그 다른 클래스를 스프링 빈으로 등록한다. 그 임의의 다른 클래스가 바로 싱글톤을 보장해준다.
-> 내가 만든 클래스가 스프링 컨테이너에 등록이 되어 있다면? -> 찾아서 반환!
-> 만약 없다면, 기존 로직을 호출해서 생성 후 스프링 컨테이너에 등록하고 반환!
만약 @Configuration 을 빼고 @Bean 만 적용한다면?
= 싱글톤 깨짐 ㅠㅠ 순수한 자바 코드 실행이 된다...ㅎ
정리
@Bean 만 사용해도 스프링 빈으로 등록되지만, 싱글톤은 보장하지 않는다. 메서드를 직접 호출하기 때문에 싱글톤을 보장하지 않는다. 스프링 설정 정보는 @Configuration 을 사용하도록 하자.
'Spring' 카테고리의 다른 글
[Spring 핵심원리 기본편] 의존관계 자동 주입! ✨ (0) | 2023.05.29 |
---|---|
[Spring 핵심원리 기본편] 컴포넌트 스캔 (1) | 2023.05.29 |
[Spring 핵심원리 기본편] 웹 애플리케이션과 싱글톤 (0) | 2023.05.21 |
[Spring 핵심원리 기본편] 스프링 컨테이너와 스프링 빈 (빈 조회) (0) | 2023.05.21 |
[Spring 핵심원리 기본편] 객체 지향 원리 적용 (->스프링 컨테이너) (0) | 2023.05.21 |
블로그의 정보
개발자 미니민의 개발로그
mini_min