devnoong.log
article thumbnail
Published 2022. 7. 28. 08:41
[SPRING] 싱글톤에 대해서 WEB/BACKEND
728x90

싱글톤이란?

  • 소프트웨어 디자인 패턴에서 사용하는 패턴으로 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴한다.
  • 즉, 클래스의 인스턴스가 하나만 생성되는것을 보장하며 인스턴스에 접근할 수 있는 전역적인 접촉점 을 제공해 하나의 인스턴스를 통해서만 접근이 가능하도록 제어하는 패턴이다.

싱글톤 사용 이유

요청이 엄청나게 많은 트래픽 사이트에서는 계속 객체를 생성하게 되면 메모리 낭비가 심하기 때문에 대규모 트래픽과 요청을 처리 할 수 있도록 사용한다.

 

사용 전

 

public class AppConfig {
	public SingleTone singleToneTest(){
		return new SingleTone();
	}
}
	@Test
	void test() {
		AppConfig appConfig = new AppConfig();
		 
		SingleTone obj1 = appConfig.singleToneTest(); //new 생성자를 통해 호출
		SingleTone obj2 = appConfig.singleToneTest();
		
		System.out.println(obj1.toString());
		System.out.println(obj2.toString());
		
		assertThat(obj1).isNotSameAs(obj2);
	}

 

서로 다른 객체가 생성 (참조 메모리 주소가 서로 다름) 된 것을 확인 할 수 있다.

 

 

사용 후

 

1. Eager Initialization (이른 초기화, Thread - safe)

 

public class SingleTone {
	private static final SingleTone instance = new SingleTone(); //전역적인 접촉점 제공
	
	private SingleTone () {} //new 생성자 호출 제한
	
	public static SingleTone getInstance() { 
		return instance;
	}
}

@Test
	void test() {
		 
		SingleTone obj1 = SingleTone.getInstance(); //static method를 통해 호출
		SingleTone obj2 = SingleTone.getInstance();
		
		System.out.println(obj1.toString());
		System.out.println(obj2.toString());
		
		assertThat(obj1).isSameAs(obj2);
	}

 

 

  1.  static 객체를 통해서 객체는 한개만 생성 할 수 있도록 전역적인 접촉점을 제공한다.
  2.  static method를 통해 외부에서 객체를 생성 할 수 있도록 제공한다.
  3.  new 생성자를 이용하여 객체를 생성하지 못하도록 private로 제한한다.

→ 여러번 호출 했음에도 불구하고, 같은 객체가 생성 (참조 메모리 주소가 같음) 된 것을 확인 할 수 있다.

 

그러나 해당 인스턴스를 사용하지 않더라도 클래스가 로딩 되자마자 생성되기때문에 메모리 낭비가 발생 할 수 있다.

 

 

2. Lazy Initialization, LazyHolder (게으른 홀더, Thread - safe)

 

public class SingleTone {
	
	private SingleTone () {} //new 생성자 호출 제한
	
	private static class InnerInsatance{
		private static final SingleTone instance = new SingleTone();

	}
	
	public static SingleTone getInstance() {
		return InnerInsatance.instance; //클래스 로딩
	}
}

 

SingleTone 클래스 로딩이 되었을때 InnerInsatance클래스는 로드되지 않고 getInstance를 호출 했을때 JVM에 로드 후 인스턴스를 생성한다.

 

가장 많이 사용하는 방법으로 알려져 있다.

싱글톤 단점

  • 싱글톤 패턴을 구현하기 위한 코드 자체가 많이 필요하다.
  • 의존관계상 클라이언트가 구체 코드에 의존하므로 DIP(의존관계 역전 원칙)를 위반합니다 ( ex : 구체클래스.getInstance())
  • 테스트하기 어렵다.
  • private 생성자로 자식 클래스를 만들 수 없다.

이러한 이유로 싱글톤 패턴은 유연성이 떨어진다는 단점이 존재한다.
일부에서는 '안티패턴'이라고도 불린다.

 

스프링 컨테이너

스프링 컨테이너는 싱글턴 패턴을 적용하지 않아도 스프링 빈 객체를 하나만 생성해서 싱글톤으로 관리한다.

이러한 기능 덕분에 싱글톤 패턴의 모든 단점을 해결하고 객체를 싱글톤으로 유지할 수 있다.

 

스프링 싱글톤 레지스트리

싱글톤 객체를 생성하고 관리해주는 기능을 싱글톤 레지스트리라고 한다.

 

싱글톤 패턴과 달리 스프링이 지지하는 객체지향적인 설계 방식의 원칙, 디자인 패턴 등을 적용하는데 아무런 제약이 없게 만들어준다.

 

즉, DIP, OCP, 테스트, private 생성자로부터 자유롭게 싱글톤을 사용할 수 있다.

 

https://withseungryu.tistory.com/74

 

싱글톤 패턴 사용시 주의해야 할 점

싱글톤 방식에서는 여러 클라이언트가 하나의 같은 객체 인스턴스를 공유하기 때문에 스프링 빈에서는 무상태(stateless)로 설계해야 한다.

 

= 객체 상태를 유지하게(stateful) 설계하면 안된다.

 

무상태란?

  • 특정 클라이언트에 의존적인 필드가 있으면 안된다.
  • 값을 변경할 수 있는 필드가 있으면 안된다.
  • 가급적 읽기만 가능해야 하고 클라이언트가 값을 변경해서는 안된다.
  • 필드 대신에 자바에서 공유되지 않는, 지역변수, 파라미터, ThreadLocal등을 사용해서 수정한다.
728x90