웹 어플리케이션과 싱글톤


지금까지 자바 기반 설정파일과 XML기반 설정파일을 읽어 BeanDefinition을 만들어 스프링 컨테이너를 생성하며 학습을 해보았다. 그럼으로써 OCP, DIP원칙을 지키며 객체지향 프로그래밍 원칙인 SOLID도 지킬 수 있었다.

하지만, 아직 고려해야할 부분이 많다. 그 중 하나가 구성영역의 appConfig.class 코드쪽인데, 우리는 보통 스프링 애플리케이션을 웹용으로 사용한다. (웹이 아닌경우도 있지만 보편적으로)

그럼 이런 웹 어플리케이션은 동시에 얼마나 많은 사람이 사용할까? 어느정도 인기가 있어서 한 순간 오만명이상이 동시에 요청을 한다고 생각해보자.

그럼 스프링 컨테이너에서 서비스 계층으로 주입되어야 할 객체들은 몇 번 생성되야하는가? 한 서비스 계층당 하나의 빈들만 주입해야한다고해도 5만번 이상 객체가 생성되서 사용되고 참조가 해제되어 GC에 수집어 정리가 되는 과정을 거쳐야 한다. 이는 몹시 비효율적이고 메모리낭비이다.

게다가 해당 빈들은 굳이 사용자마자 다른 인자값을 가지는 인스턴스가 될 일도 없다. 모두 동일한 빈 사용을위해 서비스 호출때마다 새로운 빈들이 생성 - 삭제가 되어야 한다는 것이다.

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/8daab7ea-ac5f-4de1-821a-e647a0d961ad/Untitled.png

확인 코드 작성

package hello.core.singleton;

import hello.core.AppConfig;
import hello.core.member.MemberService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class SingleToneTest {

    @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);

        //memberService != memberService2
        assertThat(memberService1).isNotSameAs(memberService2);
    }
}

그렇기에 우리는 싱글톤 패턴을 사용해 하나의 객체를 재사용하는 식으로 이런 메모리낭비를 막아야한다.

싱글톤 패턴


싱글톤 패턴에대한 자세한 내용은 이전에 포스팅했던 아래 링크를 통해 확인할 수 있다.