싱글톤이란?
생성자가 여러차례 호출되어도 실제로 생성되는 객체는 하나고 최초 생성 이후에 호출된 생성자는 최초에 생성한 객체를 리턴한다. 클래스의 인스턴스가 오직 1개만 생성되는 것을 보장하는 디자인 패턴이다.
싱글톤 구현
싱글톤 구현에서 주의 깊게 보여야 될 부분은 생성자를 Private로 생성하여,
다른 외부 클래스에서 싱글톤 클래스를 new로 구성하지 못하게 하는 부분이다.
public class SingletonSErvice{
//1. static 영역에 객체를 딱 1개만 생성해둔다.
private static final SingletonService instance = new SingletonService();
//2. public으로 열어서 객체 이스턴스가 필요하면 이 static 메서드를 통해서만 조회하도록 허용
public static SingletonService getInstance(){
return instance;
}
//3. 생성자 private으로 선언해서 외부에서 new 키워드를 사용한 객체 생성을 못하게 막는다
private SingletonService(){
}
public void login(){
System.out.println("싱글톤 객체 로직 호출");
}
}
싱글톤 패턴을 쓰는 이유
고정된 메모리 영역을 얻으면서 한번의 new로 인스턴스를 사용하기 때문에 메모리 낭비를 방비할 수 있어서 이다
싱글톤으로 만들어진 클래스의 인스턴스는 전역 인스턴스이기 때문에 다른 클래스의 인스턴스들이 데이터를 공유하기쉽다.
싱글톤의 문제점
- 싱글톤 패턴을 구현하는 코드 자체가 많이 들어간다.
- 의존관계상 클라이언트가 구체 클래스에 외존한다. ->DIP를 위반한다
- 클라이언트가 구체 클래스에 의존해서 OCP 원칙을 위반할 가능성이 높다
- 테스트하기 어렵다
- private 생성자로 자식 클래스를 만들기 어렵다
- 유연성이 떨어진다
- 안티패턴으로 불리기도 한다,
문제해결 방안
- 싱글톤 컨테이너를 사용한다.
- 스프링 컨테이너는 싱글톤 패턴의 문제점을 해결하면서, 객체 인스턴스를 싱글톤(1개 생성) 으로 관리한다.
싱글톤 방식의 주의점
- 싱글톤 패턴이든, 스프링 같은 싱글톤 컨테이너를 사용하든, 객체 인스턴스를 하나만 생성해서 공유하는 싱글톤 방식은
- 여러 클라이언트가 하나의 같은 객체 인스턴스를 공유하기 떄문에 싱글톤 객체는 상태를 유지(stateful)하게 설계하면 안된다.
- 무상태(stateless)로 설계
- 특정 클라이언트에 의존적인 필드가 있으면 안된다.
- 특정 클라이언트가 값을 변경할 수 있는 필드가 있으면 안된다
- 가급적 읽기만 가능해야 한다
- 필드 대신에 서 공유되지 않는, 지역변수, 파라미터, ThreadLocal 등을 사용해야 한다
- 스프링 빈의 필드에 공유 값을 설정하면 정말 큰 장애가 발생할 수 있다.
싱글톤 패턴의 공통적인 특징
private constructor(생성자)를 가진다는 것과, static method를 사용한다는 점이다
초기화 방식은 static키워드의 특징을 이용해서 클래스 로더가 초기화 하는 시점에서 정적 바인딩을 통해 해당 인스턴스를 메모리에 등록해서 사용하는것 이다
이른 초기화 방식은 클래스 로더에 의해 클래스가 최초로 로딩 될 때 객체가 생성되기 때문에 Thread-safe 한다
싱글턴 구현 시 중요한 점이,멀티 스레드 환경에서도 동작 가능하게끔 구현해야 한다는 것이다.
즉, Thread-safe가 보장되어야 한다
Thread-safe란?
스레드 안전(thread safety)은 멀티 스레드 프로그래밍에서 일반적으로 어떤 함수나 변수, 혹은 객체가 여러 스레드로부터 동시에 접근이 이루어져도 프로그램의 실행에 문제가 없음을 뜻한다.