(스프링의 핵심 원리 – 기본) 싱글톤


Spring 없이 순수 DI 컨테이너 테스트

public class SingletonTest {

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

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

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

        Assertions.assertThat(memberService1).isNotSameAs(memberService2);
    }
}

결과

memberService1 = hello.core.member.MemberServiceImpl@275710fc
memberService2 = hello.core.member.MemberServiceImpl@525f1e4e

  • Spring이 없는 순수한 DI 컨테이너로서 AppConfig는 각 요청에 대해 새 객체를 생성합니다.
  • 고객 트래픽이 초당 100에 도달하면 초당 100개의 객체가 생성되고 삭제됩니다.
    => 낭비되는 메모리가 많습니다.
  • 해결책은 하나의 객체만 생성되고 공유되도록 설계하는 것입니다.
    => 하나씩 일어나는 것

싱글톤 애플리케이션

public class SingletonService {

    private static final SingletonService instance = new SingletonService();

    public static SingletonService getInstance(){
        return instance;
    }
    private  SingletonService(){
        
    }
    
    public void logic(){
        System.out.println("싱글톤 객체");
    }
}
  • 신규를 비공개로 올려 차단했습니다.
  • 각 호출은 동일한 개체 인스턴스를 반환합니다.
@Test
@DisplayName("싱글톤 패턴을 사용")
void singletonServiceTest(){
    SingletonService instance1 = SingletonService.getInstance();
    SingletonService instance2 = SingletonService.getInstance();

    System.out.println("instance1 = " + instance1);
    System.out.println("instance2 = " + instance2);
    Assertions.assertThat(instance1).isSameAs(instance2);
    //same ==
    //equal equals메서드
}

결과

인스턴스1 = hello.core.singleton.SingletonService@6ee12bac
Instance2 = hello.core.singleton.SingletonService@6ee12bac

※ 싱글톤 패턴을 구현하는 방법은 여러가지가 있습니다.
이 예는 가장 쉽고 편리한 방법입니다.

싱글톤 패턴의 문제점

  • 싱글톤 패턴을 구현하는 코드가 많이 있습니다.
  • 클라이언트는 종속성에서 구체적인 클래스에 의존 => DIP 위반
  • 클라이언트가 구체적인 클래스에 의존하여 OCP 원칙을 위반할 가능성이 매우 높습니다.
  • 테스트하기 어렵다
  • 내부 속성을 변경하거나 초기화하기 어렵습니다.
  • 개인 생성자로 하위 클래스를 만드는 것은 어렵습니다.
  • 유연성이 나쁩니다.