싱글톤 패턴
싱글톤 패턴
애플리케이션이 시작될 때 어떤 클래스가 최초 한번만 메모리를 할당하고(static) 그 메모리에 인스턴스를 만들어 사용하는 디자인패턴이다.
생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나고 최초 생성 이후에 호출된 생성자는 최초에 생성한 객체를 반환한다. 딱 1개의 객체 인스턴스만 존재해야 하므로 생성자를 private로 막아서 혹시라도 외부에서 new 키워드로 객체 인스턴가 생성되는 것을 막는다. 이후 객체 인스턴스가 필요하면 getInstance()로 받아쓰기도 한다.
public class SingletonService {
private static final SingletonService instance = new SingletonService();
public static SingletonService getInstance() {
return instance;
}
private SingletonService() {
}
}
싱글톤 패턴을 사용하면 클라이언트의 요청이 올 때마다 객체를 계속 생성하는 게 아닌, 이미 만들어진 객체를 공유하여 메모리를 효율적으로 사용할 수 있지만, 아래와 같이 여러가지 문제점들을 가지고 있다.
싱글톤 패턴의 문제점
- 싱글톤 패턴을 구현하는 코드 자체가 많이 들어간다.
- 의존관계상 클라이언트가 구체 클래스에 의존한다. -> DIP를 위반한다.
- 클라이언트가 구체 클래스에 의존해서 OCP 원칙을 위반할 가능성이 높다.
- 테스트하기 어렵다.
- 내부 속성을 변경하거나 초기화 하기 어렵다.
- private 생성자로 자식 클래스를 만들기 어렵다.
- 결론적으로 유연성이 떨어진다.
- 안티패턴으로 불리기도 한다.
다행스럽게도, 스프링 컨테이너는 싱글톤 패턴의 문제점들을 해결하면서, 객체 인스턴스를 싱글톤으로 관리한다. 이렇게 싱글톤 객체를 생성하고 관리하는 기능을 싱글톤 레지스트리라 한다. 스프링의 기본 빈 등록 방식은 싱글톤이지만, 요청할 때 마다 새로운 객체를 생성해서 반환하는 기능도 제공한다.
싱글톤 방식의 주의점
- 여러 클라이언트가 하나의 같은 객체 인스턴스를 공유하기 때문에 싱글톤 객체 자체는 상태를 항상 무상태(stateless)로 설계해야 한다.
- 특정 클라이언트에 의존적인 필드가 있으면 안된다.
- 특정 클라이언트가 값을 변경할 수 있는 필드가 있으면 안된다.
- 가급적 읽기만 가능해야 한다.
- 필드 대신 자바에서 공유되지 않는 지역변수, 파라미터, ThreadLocal 등을 사용한다.
@Configuration과 바이트코드 조작의 마법
예를 들어 스프링 컨테이너가 AppConfig에 있는 메서드를 여러번 호출하는 경우가 있다고 가정을 했을 때, 얼핏 객체 인스턴스들이 여러번 생성되어 싱글톤이 깨질 것이라고 생각될 수도 있다. 이때 스프링은 클래스의 바이트코드를 조작하는 라이브러리를 사용하여 결론적으로 1번만 호출한다. AppConfig도 파라미터로 넘어가기 때문에 스프링 빈이 되게되고 이것을 출력해보면 클래스 명에 xxxCGLIB가 붙게 되는데, 이것은 내가 만든 클래스가 아니라 스프링이 CGLIB라는 바이트코드 조작 라이브러리를 사용해서 AppConfig 클래스를 상속받은 임의의 다른 클래스를 만들고, 그 다른 클래스를 스프링 빈으로 등록한 것이다. 그렇기 때문에 1번만 호출이 되어 싱글톤이 보장된다. 더 나아가 @Configuration을 적용하지않고 @Bean만 붙이면 처음에 생각했던 것과 같이 객체 인스턴스가 여러개 생성되어 싱글톤이 깨지게 된다.
※ 스프링 핵심 원리 - 기본편(김영한)을 수강하고 정리한 글입니다. inf.run/2oxX
스프링 핵심 원리 - 기본편 - 인프런
스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다. 초급 프레임워크 및 라이브러리 웹 개발 서버 개발 Back-End Spring 객체지향 온
www.inflearn.com