본문 바로가기
Spring

Singleton(싱글톤) 패턴이란?

by sangfeeeeel 2021. 12. 20.

싱글톤패턴이란?


- 클래스의 인스턴스(객체)가 딱 1개만 생성되는 것을 보장하는 디자인 패턴 입니다.

- 객체 인스턴스를 2개 이상 생성하지 못하도록 막아야 합니다.

- private 생성자를 사용해서 외부에서 임의로 new 키워드를 사용하지 못하도록 막아야 합니다.

 

 

예시코드


코드를 살펴보자면 다음과 같습니다.

1. static 영역에 객체를 미리 하나 생성해서 올려둡니다.

2. 이 객체 인스턴스가 필요하면 오직 getInstance() 메서드를 통해서만 조회할 수 있다. 이 메서드를 호출하면 

 항상 같은 인스턴스를 반환합니다.

3. 딱 1개의 객체 인스턴스만 존재해야 하므로, 생성자를 private로 막아서 혹시라도 외부에서 new 키워드로 

 객체 인스턴스가 생성되는 것을 막습니다.

 

위의 코드가 정상적으로 싱글톤 패턴에 맞게 작동하는지 알아보기 위하여 테스트 코드를 통해 확인해 보겠습니다.

위의 테스트코드 결과를 미리 예상해 본다면, 객체를 2개 호출하더라도 같은 객체로 호출될것입니다. 결과를 확인해보면

같은 객체이고, 테스트도 통과하는 것을 확인할 수 있습니다.

 

하지만 이런 싱글톤 패턴은 문제점 또한 갖고 있습니다. 

 

 

싱글톤 패턴 문제점?


1. 싱글톤 패턴을 구현하는 코드 자체가 많이 들어갑니다.

2. 의존관계상 클라이언트가 구체 클래스에 의존하는것 -> DIP를 위반하는것 입니다.

3. 클라이언트가 구체 클래스에 의존해서 OCP 원칙을 위반할 가능성이 높습니다.

그 외에도 테스트가 어렵다, 내부 속성을 변경하거나 초기화 하기 어렵다 같은 문제점들이 있습니다. 이와 같은 문제점들을 해결하기 위해서

나온것이 스프링 컨테이너 입니다.

 

 

스프링 컨테이너


- 스프링 컨테이너는 싱글톤 패턴을 적용하지 않아도, 객체 인스턴스를 싱글톤으로 관리합니다.

- 스프링 컨테이너는 싱글톤 컨테이너 역할을 한다. 이렇게 싱글톤 객체를 생성하고 관리하는 기능을 싱글톤 레지스트리라 합니다.

- 스프링 컨테이너의 이런 기능 덕분에 싱글턴 패턴의 모든 단점을 해결하면서 객체를 싱글톤으로 유지할 수 있습니다.

 (싱글톤 패턴을 위한 지저분한 코드가 필요 없다, DIP/OCP/Test/ private생성자로 부터 자유롭게 싱글톤을 사용할 수 있습니다.

 

 

스프링 컨테이너를 사용하는 테스트 코드


첫줄의 ApplicationContext가 스프링 컨테이너를 사용해 싱글톤을 확인하는 코드 입니다. 결과를 살펴보자면 

객체가 같은 싱글톤을 유지하는 것을 알 수 있습니다. 

이러한 스프링 컨테이너 덕분에 고객의 요청이 올 때 마다 객체를 생성하는 것이 아니라,  이미 만들어진 객체를 공유해서 효율적으로

재사용 할 수 있습니다.

이렇게 싱글톤 패턴이든, 스프링 컨테이너를 활용하든,  싱글톤 방식은 여러 클라이언트가 하나의 객체 인스턴스를 공유하기 때문에

싱글톤 객체는 상태를 유지(stateful)하게 설계하면 안되고 무상태(stateless)로 설계해야 합니다.

 

 

싱글톤 방식의 주의점


무상태(stateless)로 설계해야 한다.

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

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

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

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

 

 

상태를 유지하게 발생할 경우


위의 코드를 아래 코드처럼 테스트를 돌려보면,

A사용자의 주문금액을 조회한다면 price = 10000이 나와야 합니다. 하지만 결과를 보면

이처럼 price = 20000 이라는 결과가 나옵니다. 왜 그럴까요? 

StatefulService의 price 필드는 공유되는 필드이기 때문에, 어떤 클라이언트가 값을 변경하자 값이 변한것 입니다.

이러한 경우가 실무에서 발생한다면 정말 큰 문제가 발생하기 때문에, 항상 조심해야 하며

스프링 빈은 항상 무상태(stateless)로 설계해야 합니다!