Free Lines Arrow
본문 바로가기
Spring/spring 기초 스터디

[Spring] 웹 애플리케이션과 싱글톤2

by skahn1215 2021. 5. 5.
728x90
반응형

싱글톤의 문제점 과 해결법

 

앞서 웹 어플리케이션에서 싱글톤을 왜 사용하는지 알아 봤다.

이제는 싱글톤의 문제점과 해결법을 알아보자.

 

vprog1215.tistory.com/44

 

웹 애플리케이션과 싱글톤1

웹 어플리케이션과 싱글톤은 어떠한 관계가 있을까? 스프링의 태생 1. 기업용 온라인 서비스 기술을 지원하기 위해 탄생. 2. 대부분의 스프링 어플리케이션은 웹 어플리케이션이다. 3. 웹 애플리

vprog1215.tistory.com

 

 

 

 

문제점

 

1. 싱글톤의 공유변수 사용을 주의 하자.

 

2. 싱글톤 패턴이든, 스프링 같은 싱글톤 컨테이너를 사용하든, 객체 인스턴스를 하나만 생성해서 공유하는 싱 글톤 방식은 여러 클라이언트가 하나의 같은 객체 인스턴스를 공유하기 때문에 싱글톤 객체는 상태를 유지 (stateful)하게 설계하면 안된다

 

3. 무상태로 설계 해야된다.

    - 특정 클라이언트에 의존적인 필드가 있으면 안된다.

    - 특정 클라이언트가 값을 변경할 수 있는 필드가 있으면 안된다.

    - 가급적 읽기만 가능해야 한다.

    - 필드 대신에 자바에서 공유되지 않는 변수, 지역변수, 파라미터 ThreadLocal등을 사용해야 한다.

 

4. 그렇지 않으면 큰 장애 발생.

    - 어떻게 장애가 발생할까? 앞서 싱글톤의 개념은 "하나의 어플케이션에서 하나의 객체만 생성한다고 헀다."

    - 그럼 공유변수를 사용하게 되면 어떻게 될까?

 

5. 공유변수 사용시 발생되는 문제점

    - 우리가 만든 싱글톤에 price 라는 변수가 있다고 가정하자

    - A 사용자가 10000 을 주문하고 price에 그 값을 저장한다.

    - B 사용자가 20000 을 주문하고 price에 그 값을 저장한다.

    - 문제가 벌써 발생했다 그럼 앞에 저장한 10000은 20000 으로 변경이 된다.

    - 망한것이다.

 

 

 

 

문제 코드

package hello.core.singletone;

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;
    }
}
package hello.core.singletone;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;


public class StatefulServiceTest {

    @Test
    void statefulServiceSingleton() {
        AnnotationConfigApplicationContext 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();
        System.out.println("price = " + price);

        Assertions.assertThat(statefulService1.getPrice()).isEqualTo(20000);
    }

    static class TestConfig {

        @Bean
        public  StatefulService statefulService() {
            return new StatefulService();
        }
    }

}

 

 

 

 

문제 해결코드

package hello.core.singletone;

public class StatefulService {
    //private int price;

    public int order(String name, int price)
    {
        System.out.println("name = " + name + " price = "+price);
        //this.price = price;
        return price;
    }

    //public int getPrice() {
    //   return price;
    //}
}

 

package hello.core.singletone;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;


public class StatefulServiceTest {

    @Test
    void statefulServiceSingleton() {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
        StatefulService statefulService1 = ac.getBean(StatefulService.class);
        StatefulService statefulService2 = ac.getBean(StatefulService.class);

        //ThreadA: A 사용자가 10000원 주문
        int useAPrice = statefulService1.order("userA", 10000);

        //ThreadB: B 사용자가 20000원 주문
        int useBPrice = statefulService1.order("userB", 20000);

        //ThreadA: 사용자A 주문 금액 조회
        //int price  = statefulService1.getPrice();
        System.out.println("price = " + useAPrice);

        //Assertions.assertThat(statefulService1.getPrice()).isEqualTo(20000);
    }

    static class TestConfig {

        @Bean
        public  StatefulService statefulService() {
            return new StatefulService();
        }
    }

}

 

변경된 코드를 보면 price값을 저장하거나 공유하는 부분을 삭제하였다.

이런걸 무상태라고 한다.

 

 

 

 

 

 

참고: www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/lecture/55364?tab=note

 

스프링 핵심 원리 - 기본편 - 인프런 | 학습 페이지

지식을 나누면 반드시 나에게 돌아옵니다. 인프런을 통해 나의 지식에 가치를 부여하세요....

www.inflearn.com

 

728x90
반응형

댓글