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

jy9922·2022년 8월 23일
0

Spring

목록 보기
27/34
post-thumbnail

싱글톤 컨테이너

  • 스프링은 태생이 기업용 온라인 서비스 기술을 지원하기 위해 탄생했다.
  • 대부분의 스프링 애플리케이션은 웹 애플리케이션!
  • 웹 애플리케이션은 보통 여러 고객이 동시에 요청을 한다.

  • 고객이 3번 요청하면 객체가 3번 생성되어야 하는 문제가 발생한다.

스프링이 없는 순수한 DI 컨테이너 테스트

SingletonTest

public class SingletonTest {
    @Test
    @DisplayName("스프링 없는 순수한 DI 컨테이너")
    void pureContainer(){
        AppConfig appConfig = new AppConfig();
//      1. 조회 : 호출할 때마다 객체를 생성
        MemberService memberService1 = appConfig.memberService();

//      2. 조회 : 호출할 때마다 객체를 생성
        MemberService memberService2 = appConfig.memberService();

//      3. 참조값이 다른 것을 확인
        System.out.println("memberService1 = " + memberService1);
        System.out.println("memberService2 = " + memberService2);

//      memberService1과 memberService2가 다른지 자동화로 만들어보자
        assertThat(memberService1).isNotSameAs(memberService2);
    }
}

결과를 보면 memberService1과 memberService2는 서로 다른 객체이다. 즉, 다른 객체가 생성되어 JVM에 각각 올라가게 된다.

  • 스프링 없는 순수한 DI 컨테이너인 AppConfig는 요청을 할 때 마다 객체를 새로 생성한다.
  • 고객 트래픽이 초당 100이 나오면 초당 100개 객체가 생성되고 소멸된다.
    • 메모리 낭비가 심하다!
  • 해결방안은 해당 객체가 딱 1개만 생성되고, 공유하도록 설계하면 된다.
    • 싱글톤 패턴

싱글톤 패턴 🌈

  • 클래스 인스턴스가 딱 1개만 생성되는 것을 보장하는 디자인 패턴
  • 객체 인스턴스를 2개 이상 생성하지 못하도록 막아야 한다.

싱글톤 패턴을 적용한 예제 코드

public class SingletonService {

    // 자바의 static 영역 공부해보세요!
    private static final SingletonService instance = new SingletonService();

    public static SingletonService getInstance() {
        return instance;
    }

    // 생성자를 private으로 설정해서 밖에서 못 만들게 설정
    private SingletonService() {

    }

    public void logic() {
        System.out.println("싱글톤 객체 로직 호출");
    }
}
  • static 영역에 객체 instance를 미리 하나 생성해서 올려둔다.
  • 이 객체 인스턴스가 필요하면 오직 getInstance() 메서드를 통해서만 조회할 수 있다.
    • 이 메서드를 호출하면 항상 같은 인스턴스만 생성한다.
  • 딱 1개의 객체 인스턴스만 존재해야 하므로, 생성자를 private으로 막아서 혹시라도 외부에서 new키워드로 객체 인스턴스가 생성되는 것을 막는다.

싱글톤 패턴 적용 테스트

 @Test
    @DisplayName("싱글톤 패턴을 적용한 객체 사용")
    void SingletonServiceTest(){
        SingletonService singletonService1 = SingletonService.getInstance();
        SingletonService singletonService2 = SingletonService.getInstance();

        System.out.println("singletonService1 = " + singletonService1);
        System.out.println("singletonService2 = " + singletonService2);

        assertThat(singletonService1).isSameAs(singletonService2);
        // same (==)
        // equal (Java의 eqauls 메서드)
    }

  • private으로 new 키워드를 막아두었다.
  • 호출할 때마다 같은 객체 인스턴스를 반환하는 것을 확인할 수 있다.

    싱글톤 패턴을 적용하면 고객의 요청이 올 때마다 객체를 생성하는 것이 아니라, 이미 만들어진 객체를 공유해서 효율적으로 사용할 수 있다.
    하지만 싱글톤 패턴은 다음과 같은 수 많은 문제점을 가지고 있다.

싱글톤 패턴 문제점 😱

  • 싱글톤 패턴을 구현하는 코드 자체가 많이 들어간다.
  • 의존관계상 클라이언트가 구체클래스에 의존한다.
    • 구체클래스.getInstance()
    • DIP를 위반한다.
  • 클라이언트가 구체 클래스에 의존해서 OCP 원칙을 위반할 가능성이 높다.
  • 테스트 하기가 어렵다.
  • 내부 속성을 변경하거나 초기화 하기 어렵다.
  • private 생성자로 자식 클래스를 만들기 어렵다.

💡 결론적으로 유연성이 떨어진다.
💡 안티패턴으로 불리기도 한다.

위 싱글톤 패턴의 문제점을 제거하고, 객체를 싱글톤으로 관리해주는 싱글톤 컨테이너에 대해 알아보자!

0개의 댓글