1. 웹 애플리케이션과 싱글톤
- 배경: 스프링은 본래 기업용 온라인 서비스 기술을 지원하기 위해 탄생했으며, 대부분의 스프링 앱은 웹 앱입니다.
- 특징: 웹 애플리케이션은 보통 여러 고객이 동시에 요청을 합니다.
- 문제점: 우리가 만들었던 순수한 DI 컨테이너인 AppConfig는 요청을 할 때마다 객체를 새로 생성합니다.
- 고객 트래픽이 초당 100이면, 초당 100개의 객체가 생성되고 소멸됩니다. → 메모리 낭비가 심함.

- 해결방안: 해당 객체가 딱 1개만 생성되고, 공유하도록 설계하는 싱글톤 패턴을 사용합니다.
[테스트 코드] 스프링 없는 순수한 DI 컨테이너
package com.example.spring_study.singleton;
import com.example.spring_study.AppConfig;
import com.example.spring_study.member.MemberService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import static org.assertj.core.api.Assertions.*;
public class SingletonTest {
@Test
@DisplayName("스프링 없는 순수한 DI 컨테이너")
void pureContainer(){
// 순수 자바 방식으로 AppConfig 사용(AppConfig에 어노테이션(@)을 이용하여 작성되어 있더라고, Spring 방식(ApplicationContext)으로 불러오지 않으면 효력 x)
AppConfig appConfig = new AppConfig();
//1. 조회 : 호출할 떄마다 객체를 생성
MemberService memberService1 = appConfig.memberService();
//2. 조회 : 호출할 떄마다 객체를 생성
MemberService memberService2 = appConfig.memberService();
// 참조값이 다른 것을 확인
// 메모리에 객체가 계속 생성됨(웹은 여러 사용자가 요청을 계속 보내는 구조인데, 이러면 객체가 계속 쌓임)
System.out.println("memberService1 = " + memberService1);
System.out.println("memberService2 = " + memberService2);
// memberService1 != memberService2
assertThat(memberService1).isNotSameAs(memberService2);
// 이렇게 호출할 때마다 객체를 생성하는 문제를 해결하기 위해서 객체를 1개만 생성하는 Singleton 방식을 사용
}
}
2. 싱글톤 패턴 (Singleton Pattern)
- 정의: 클래스의 인스턴스가 딱 1개만 생성되는 것을 보장하는 디자인 패턴입니다.
- 제약: 객체 인스턴스를 2개 이상 생성하지 못하도록 막아야 합니다.
- private 생성자를 사용하여 외부에서 임의로 new 키워드를 사용하지 못하도록 막습니다.
[예제 코드] 싱글톤 패턴 적용
package com.example.spring_study.singleton;
public class SingletonService {
// static으로 class 레벨에 올라가기 때문에 객체가 1개만 존재
private static final SingletonService instance = new SingletonService();
// public인 getInstance()로 생성되어 있는 Singleton 객체를 불러옴(항상 같은 인스턴스를 불러옴)
public static SingletonService getInstance() {
return instance;
}
// private 이기 때문에, 외부에서는 Singleton 객체를 생성할 수 없음
private SingletonService() {
}
public void logic(){
System.out.println("싱글톤 객체 로직 호출");
}
}
[테스트 코드] 싱글톤 패턴을 적용한 객체 사용
@Test
@DisplayName("싱글톤 패턴을 적용한 객체 사용")
void singletonServiceTest(){
// new SingletonService(); // -> private이기 때문에 이 방식으로 싱글톤 객체 생성 시도를 막음
SingletonService singletonService1 = SingletonService.getInstance();
SingletonService singletonService2 = SingletonService.getInstance();
// 참조값이 같은 것을 확인
System.out.println("singletonService1 = " + singletonService1);
System.out.println("singletonService2 = " + singletonService2);
assertThat(singletonService1).isSameAs(singletonService2);
// same -> 인스턴스가 같은지
// equal = 내용이 같은지
}
3. 싱글톤 패턴의 문제점
싱글톤 패턴을 적용하면 효율적이지만, 다음과 같은 수많은 문제점이 있음
- 싱글톤 패턴을 구현하는 코드 자체가 많이 들어갑니다.
- 클라이언트가 구체 클래스에 의존합니다. → DIP 위반
- 클라이언트가 구체 클래스에 의존해서 OCP 원칙을 위반할 가능성이 높습니다.
- 테스트하기 어렵습니다.
- 내부 속성을 변경하거나 초기화하기 어렵습니다.
- private 생성자로 자식 클래스를 만들기 어렵습니다.
- 결론적으로 유연성이 떨어지며, 안티패턴으로 불리기도 합니다.
4. 싱글톤 컨테이너 (Spring)
스프링 컨테이너는 싱글톤 패턴의 문제점을 해결하면서, 객체 인스턴스를 싱글톤으로 관리합니다.
- 특징: 싱글톤 패턴을 적용하지 않아도 객체 인스턴스를 하나만 생성해서 관리합니다.
- 싱글톤 레지스트리: 싱글톤 객체를 생성하고 관리하는 스프링 컨테이너의 기능을 말합니다.
- 장점: * 싱글톤 패턴을 위한 지저분한 코드가 들어가지 않습니다.
- DIP, OCP, 테스트, private 생성자로부터 자유롭게 싱글톤을 사용할 수 있습니다.

[테스트 코드] 스프링 컨테이너와 싱글톤
@Test
@DisplayName("스프링 컨테이너와 싱글톤")
void springContainer(){
// AppConfig appConfig = new AppConfig(); // 순수 자바 방식
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class); // Spring 방식
//1. 조회 : 호출할 떄마다 객체를 생성
MemberService memberService1 = ac.getBean("memberService",MemberService.class);
//2. 조회 : 호출할 떄마다 객체를 생성
MemberService memberService2 = ac.getBean("memberService",MemberService.class);
// 참조값이 같은 것을 확인(Spring의 Spring Container에서는 Bean을 자동으로 Singleton 패턴으로 관리)
// Spring의 기본 Bean 등록 방식은 Singleton이지만, 요청할 때마다 새로운 객체를 생성해서 반환하는 기능도 제공(이후 Bean Scope에서 다룸)
System.out.println("memberService1 = " + memberService1);
System.out.println("memberService2 = " + memberService2);
// memberService1 == memberService2
assertThat(memberService1).isSameAs(memberService2);
// 이렇게 호출할 때마다 객체를 생성하는 문제를 해결하기 위해서 객체를 1개만 생성하는 Singleton 방식을 사용
}
5. 추가 사항
- 스프링 컨테이너 덕분에 고객의 요청이 올 때마다 객체를 생성하는 것이 아니라, 이미 만들어진 객체를 공유해서 효율적으로 재사용할 수 있습니다.
- 참고: 스프링의 기본 빈 등록 방식은 싱글톤이지만, 요청할 때마다 새로운 객체를 생성하는 기능(빈 스코프)도 제공합니다.
'INFLEARN' 카테고리의 다른 글
| [스프링 핵심 원리 - 기본편] 10. ComponentScan (0) | 2026.03.15 |
|---|---|
| [스프링 핵심 원리 - 기본편] 9. @Configuration과 Singleton 보장 (1) | 2026.03.13 |
| [스프링 핵심 원리 - 기본편] 7. BeanFactory와 ApplicationContext (0) | 2026.03.13 |
| [스프링 핵심 원리 - 기본편] 6. 스프링 빈 조회 - 기본, 동일타입이 둘 이상, 상속 (0) | 2026.03.13 |
| [스프링 핵심 원리 - 기본편] 5. Spring Container (0) | 2026.03.13 |