대부분의 스프링 애플리케이션은 웹 애플리케이션이다. 물론, 웹이 아닌 애플리케이션도 개발 가능하다.
만약, 웹사이트에서 여러 고객이 동시에 많은 요청하는 경우에 대비해 어떻게 개발을 해야할까?
위 사진처럼 요청이 이뤄질 때마다, 객체를 새로 생성하여 반환하는 식으로 개발을 하게 된다고 가정해보자
고객 트래픽이 초당 100일 경우, 초당 100개의 객체가 생성되고 소멸되면서 메모리 낭비가 심해질 것이다. 이 방법은 좋지 않은 선택이라는 소리다.
바로 해당 객체가 1개만 생성되어, 공유하도록 설계하는 Singleton Pattern
을 사용하여 위 문제점을 해결할 수 있다. !
🖐️ 싱글톤 패턴이란 ?
: 클래스의 인스턴스가 딱 1개만 생성되는 것을 보장하는 디자인 패턴으로, 2개 이상 생성하지 못하도록 설계하는 패턴이다.
간단한 예제를 통해 싱글톤 패턴에 대해 알아보자.
public class SingletonPattern {
//1. static 영역에 객체를 딱 1개만 생성해둔다.
private static final SingletonPattern instance = new SingletonPattern();
//2. public으로 열어서 객체 인스턴스가 필요하면 이 static 메서드를 통해서만 조회하도록 허용
public static SingletonPattern getInstance() {
return instance;
}
//3. 생성자를 private으로 선언해서 외부에서 new 키워드를 사용한 객체 생성을 못하게 막는다.
private SingletonPattern() { }
}
싱글톤 패턴을 구현하는 방법은 여러가지로, 싱글톤 패턴을 구현하는 방법에 대해 알아보자.
싱글톤 패턴을 적용했을 때 생기는 문제점은 없을까?
🖐️ 1. private 생성자로 인해 자식 클래스를 만들기 어렵다.
🖐️ 2. 내부 속성 변경/초기화하기 어렵다.
🖐️ 3. 의존 관계 상 클라이언트가 구체 클래스에 의존해 DIP와 OCP를 위반할 가능성이 높아짐
스프링 컨테이너는 싱글톤 패턴의 문제점을 해결하고, 객체 인스턴스를 싱글톤으로 관리
싱글톤 컨테이너는 싱글톤 패턴을 적용하지 않아도, 객체 인스턴스를 스프링 빈으로 등록하여 싱글톤으로 관리한다.
즉, private 생성자
와 DIP
, OCP
그리고 테스트의 어려움으로부터 자유롭게 사용할 수 있다.
위 그림과 같이 이미 만들어진 객체를 공유해 효율적으로 재사용할 수 있다.
스프링의 기본 빈 등록 방식은 싱글톤이다.
요청할 때마다 새로운 객체를 생성해서 반환하는 기능도 제공 (Bean Scope
)
스프링 같은 싱글톤 컨테이너를 사용하더라도 주의할 점이 있다.
🖐️ 여러 클라이언트가 하나의 같은 객체 인스턴스를 공유하기에 싱글톤 객체는 상태를 유지(stateful)하게 설계하면 안된다. 무상태(stateless)로 설계해야 한다!
🖐️ 특정 클라이언트에 의존적인 필드와 값을 변경할 수 있는 필드가 있으면 안된다.
🖐️ 필드 대신에 자바에서 공유되지 않는, 지역변수, 파라미터, ThreadLocal 등을 사용해야 한다.
❗ 필드에 공유 값을 설정하면 정말 큰 장애가 발생할 수 있기에 주의해야 한다.
스프링 컨테이너는 싱글톤 레지스트리다. 따라서 스프링 빈이 싱글톤이 되도록 보장해주어야 한다.
어떻게 싱글톤을 보장하는 것일까 ?
* 여기서 설정 정보 클래스인 AppConfig
는 @Configuration
애노테이션이 적용된 상태
이는 스프링이 CGLIB
라이브러리를 사용해서 AppConfig
클래스를 상속받은 임의의 다른 클래스를 만들고, 그 다른 클래스를 스프링 빈으로 등록한다.
그렇게 등록된 스프링 빈을 CGLIB
라이브러리을 통해 존재하는 스프링 빈이 호출되면 존재하는 빈을 반환하는 것으로 싱글톤을 보장한다.
@Configuration
을 적용하지 않고,@Bean
애노테이션만 적용 시 , 싱글톤 보장 X
스프링 설정 정보는 항상@Configuration
을 사용하자.
📌 본 포스트는 스프링 핵심 원리 - 기본편 통해 학습한 내용을 요약 및 정리한 것입니다.