Singleton 보장 방법
책/Effective Java

Singleton 보장 방법

728x90
반응형
private 생성자 / 열거 타입으로 Singleton을 보장하자

 

Singleton

 

인스턴스를 오직 하나만 생성할 수 있는 클래스
cf) instance =?

 

싱글턴이 필요한 상황 

  • 무상태 객체 - 함수
  • 설계상 유일성이 보장되야 하는 시스템 컴포넌트 (ex -  Spring 컨테이너가 각 클래스에 대해 딱 한개의 인스턴스만 생성)
  • Thread-safe가 보장되어야 하는 상황 

 

클래스를 싱글턴으로 만든다.
→ 해당 클래스를 사용하는 클라이언트를 테스트하기 어려워질 수 있다. 

이유 :

  • 하나의 자원을 공유하기 때문에 프로덕션 DB에 사용되는 싱글턴 클래스라면 인스턴스가 하나이다.  따라서 싱글턴 인스턴스를 가짜(mock) 구현으로 대체할 수 없기 때문이다. 

 

 

 


Singleton 을 만드는 방법 

 

방법 #1 - public static final 필드 방식 

  • 해당 instance 를 public static final 필드로 만들고 생성자의 접근제어자를 private으로 설정 
  • private 생성자는 static 변수를 초기화할 때 딱 한 번만 호출된다. 
  • 이 방식의 장점 
    • 해당 클래스가 싱글턴임이 명백히 보장 및 간결
    • 해당 클래서가 싱글턴임이 API에 명확히 드러남 

 

예외적으로 private 접근 방법 
Reflection API - AccessibleObject.setAccessible 사용 

이러한 무단 접근을 막기 위해서는 생성자를 수정하여 두 번째 객체 생성시 예외 처리 

instance 두 번째 객체 생성 방지

 


방법 #2 - static factory 방식 

public class Singleton{

	...

	public static Singleton getInstance(){return Instance;}
}

 

  • getInstance()는 항상 같은 객체를 참조하기 때문에 다른 인스턴스가 생성되지 않는다. 
  • 장점
    • 팩토리 메서드만 수정하면 언제든 싱글턴이 아니게할 수 있음
    • 정적 팩토리를 Generic Singleton 팩토리로 만들어 타입에 유연하게 대처가 가능
    • 정적 팩토리 메서드 참조를 공급자(supplier)로 사용할 수 있다. 
      • Singleton::getInstance → Supplier(Singleton)

 


방법 #3 - 열거(Enum) 타입 방식 

  • 대부분 상황에서 원소가 하나뿐인 열거 타입은 싱글턴 생성 방식에 가장 좋은 방법
  • public 필드 방식과 비슷, 하지만 더욱 간결하고 간단하게 직렬화(Serialization) 가능
Serialization 

- 자바 시스템 내부에서 사용되는 객체 또는 데이터를 외부의 자바 시스템에서도 사용할 수 있도록 바이트 형태로 데이터 변환하거나 , 바이트로 변환된 데이터를 다시 객체로 변환하는 기술(역직렬화)

- JVM의 메모리에 상주(힙 , 스택)되어 있는 객체 데이터를 바이트 형태로 변환하는 기술 , 직렬화된 바이트 데이터를 객체로 변환하여 JVM 에 상주시키는 형태 
  • 복잡한 직렬화 상황 혹은 리플렉션 공격에서도 다른 인스턴스 생성을 방지 
  • 만들고자 하는 싱글턴이 다른 클래스를 상속해야한다면 이 방법은 사용할 수 없음 
public enum Singleton{
	INSTANCE;
    
    public void leaveTheBuilding(){...}

}

 


직렬화 (Serialization)

  • 방법 1과 방법 2의 경우 직렬화에 사용시에 역직렬화를 진행할 경우 같은 타입의 인스턴스가 여러개 생길 수 있음. 
  • 이러한 문제를 해결하기 위해서는 모든 인스턴스 필드에 transient를 추가하고 readResolve 메서드를 아래와 같이 구현 
private Object readResolve(){
	return INSTANCE;
}
transient

해당 데이터(객체)를 직렬화할 때 제외하고자 할 경우 선언하는 키워드 
ex) password 

 

728x90
반응형