[스프링] 싱글톤과 스프링 컨테이너에 대하여

2025. 6. 26. 20:39·스프링

웹 애플리케이션은 수많은 사용자의 요청을 처리해야 한다.
예를 들어, 초당 100명이 서버에 요청을 보내면 객체도 초당 100개씩 생성되고, 소멸된다.

이러한 구조는 메모리 낭비가 심하고 성능에도 큰 영향을 준다.
매번 객체를 새로 만드는 것이 아니라, 하나의 객체를 공유해서 사용하는 구조가 필요하다.
이런 배경에서 등장한 것이 바로 싱글톤(Singleton) 패턴이다.

 

싱글톤 패턴이란?

싱글톤 패턴은 객체를 단 하나만 생성해서 여러 곳에서 공유하도록 설계하는 패턴이다.

public class SingletonService {
    private static final SingletonService instance = new SingletonService();

    private SingletonService() {} // private 생성자

    public static SingletonService getInstance() {
        return instance;
    }
}

위 코드처럼 클래스 내부에서 객체를 하나만 생성하고, 외부에서는 정적 메서드를 통해 그 객체를 사용한다.
이러면 메모리 낭비 없이 하나의 객체를 여러 요청에서 재사용할 수 있다.

 

그런데, 싱글톤 패턴은 완벽하지 않다

싱글톤은 유용하지만, 직접 구현하면 여러 가지 문제점이 발생한다.

  • 구현 코드가 복잡하다: private 생성자, static 메서드 등 지저분한 코드가 필요하다.
  • DIP 위반: 클라이언트가 구체 클래스에 의존하게 된다.
  • OCP 위반 가능성: 구현체를 바꾸기 어려워 확장성이 떨어진다.
  • 테스트 어려움: 객체 상태가 공유되기 때문에 테스트 환경 구성에 제약이 많다.
  • 유연성 부족: private 생성자 때문에 상속이 불가능하다.
  • 초기화 문제: 객체 내부 속성을 다시 초기화하거나 변경하기 어렵다.

그래서 이 싱글톤 패턴은 종종 안티패턴으로 불리기도 한다.

 

스프링의 대답: 싱글톤 컨테이너

스프링은 이러한 문제를 아주 세련된 방식으로 해결한다.
스프링 컨테이너는 우리가 직접 싱글톤 코드를 작성하지 않아도, 객체를 자동으로 싱글톤으로 관리해준다.

 

즉, 우리가 @Component나 @Service, @Bean으로 등록한 객체는
스프링 컨테이너가 딱 하나만 생성해서 계속 재사용한다.

이런 구조를 우리는 싱글톤 컨테이너라고 부른다.


더 정확히 말하면, 스프링 컨테이너는 싱글톤 레지스트리(singleton registry)로서 객체를 하나만 생성하고 계속 보관하면서, 필요한 곳에 꺼내서 주입해준다.

 

그럼, 싱글톤 컨테이너는 어떻게 동작할까?

예를 들어 다음과 같은 설정 클래스가 있다고 하자.

@Configuration
public class AppConfig {

    @Bean
    public MemberService memberService() {
        return new MemberService(memberRepository()); //1번
    }

    @Bean
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository(); //2번
    }
}

위 코드를 보면 memberRepository()가 두 번 호출되는 것처럼 보이지만, 스프링은 실제로 MemoryMemberRepository 객체를 한 번만 생성한다.

 

이게 가능한 이유는 스프링이 @Configuration 클래스인 AppConfig를 CGLIB이라는 바이트코드 조작 라이브러리를 이용해 프록시 객체로 바꿔버리기 때문이다.

 

CGLIB의 마법

실제로 스프링이 실행되면, AppConfig 클래스는 우리가 만든 그 클래스가 아니다.
내부적으로는 다음과 같이 조작된 형태라고 볼 수 있다.

@Bean
public MemberRepository memberRepository() {
    if (스프링 컨테이너에 이미 등록된 객체가 있으면) {
        return 기존 객체;
    } else {
        MemoryMemberRepository 객체를 생성하고 컨테이너에 등록 후 반환;
    }
}

 

즉, @Configuration이 붙은 클래스는 단순한 자바 클래스가 아니라
프록시 객체로 바뀌고, 내부 메서드들은 호출될 때마다 싱글톤 여부를 체크한다.

 

이 덕분에 우리는 @Bean 메서드를 여러 번 호출하더라도
객체는 한 번만 생성되고 공유된다.
이게 바로 스프링이 제공하는 진짜 싱글톤 관리 방식이다.

 

 

싱글톤 방식의 문제점 - 공유 필드와 상태 유지 주의

싱글톤 패턴이든, 스프링의 싱글톤 컨테이너든, 객체를 하나만 생성해서 여러 요청에서 공유한다는 점은 동일하다.
이 구조 자체는 효율적이지만, 그만큼 설계할 때 주의해야 할 부분도 많다.

대표적인 예가 상태를 가진 싱글톤 객체다.
싱글톤 객체는 여러 클라이언트가 동시에 접근하므로,
그 안에 특정 요청이나 사용자에 따라 달라지는 데이터를 필드에 저장하면
데이터 충돌이나 동시성 문제가 발생할 수 있다.

작성자는 실무에 있지는 않지만, 여러 개발자들의 이야기나 사례를 보면
실제로 이런 문제가 발생해서 원인을 찾기 어렵고 치명적인 장애로 이어진 경우가 많다고 한다.
몇 년에 한 번꼴로 꼭 이런 일이 발생한다는 말도 들었다.

특히, 스프링 빈의 필드에 공유되는 값을 저장하는 방식은
한 명의 사용자 데이터가 다른 사용자에게 노출되거나, 데이터가 뒤섞이는 등
예상치 못한 버그를 만들 수 있다.

이런 문제를 방지하려면 다음과 같은 원칙을 지켜야 한다:

  • 스프링 빈은 무상태(stateless)로 설계해야 한다
  • 특정 요청에 따른 데이터는 지역 변수나 파라미터로 처리해야 한다
  • 공유 필드는 절대 피하고, 필요한 경우에는 ThreadLocal 같은 방법을 고려한다
  • 가능한 한 빈 내부 값은 읽기 전용(불변)으로 유지한다

즉, 하나의 객체를 공유하는 구조에서는 설계 자체가 매우 중요하다는 것이다.
상태를 잘못 다루면 아무리 좋은 구조도 무너지게 된다.

 

 

결론적으로 스프링 컨테이너는 개발자가 직접 싱글톤 패턴을 구현하지 않아도 객체를 자동으로 하나만 생성하고 공유한다.그리고 다음과 같은 이점을 제공한다.

  • 지저분한 싱글톤 구현 코드가 필요 없다.
  • DIP와 OCP 같은 객체지향 설계 원칙을 지킬 수 있다.
  • 테스트 환경에서도 유연하게 동작한다.
  • 내부 속성 변경, 초기화가 가능하다.
  • 생성자도 자유롭게 활용할 수 있다.

즉, 싱글톤 패턴의 단점은 없애고, 장점만 남긴 구조가 바로 스프링의 싱글톤 컨테이너다.

스프링은 객체를 하나만 생성하고 재사용하면서도 객체 지향 원칙과 유연성을 해치지 않는 구조를 제공한다.

싱글톤은 이제 더 이상 직접 구현하지 않아도 된다.
스프링이 모든 것을 대신 처리해준다.

'스프링' 카테고리의 다른 글

[스프링] 빈 스코프  (1) 2025.07.24
[스프링] 빈 생명주기 콜백  (3) 2025.07.24
[스프링] 의존관계 자동 주입에 대하여  (0) 2025.06.26
[스프링] 스프링 컨테이너와 빈(Bean)은 왜 필요한가?  (0) 2025.06.26
[스프링] 스프링이란 무엇일까?  (0) 2025.06.26
'스프링' 카테고리의 다른 글
  • [스프링] 빈 생명주기 콜백
  • [스프링] 의존관계 자동 주입에 대하여
  • [스프링] 스프링 컨테이너와 빈(Bean)은 왜 필요한가?
  • [스프링] 스프링이란 무엇일까?
0kingki_
0kingki_
자바 + 스프링 웹 개발
  • 0kingki_
    0kingki_
    0kingki_
  • 전체
    오늘
    어제
    • 분류 전체보기 (134)
      • 코딩 테스트 (54)
      • 자바 (21)
      • 스프링 (27)
      • 타임리프 (16)
      • 스프링 데이터 JPA (8)
      • 최적화 (2)
      • QueryDSL (4)
      • AWS (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    dfs
    자바
    mvc
    스프링
    thymeleaf
    스프링 컨테이너
    재귀
    쿼리dsl
    쿼리
    객체지향
    QueryDSL
    코딩테스트
    불변객체
    최적화
    예외처리
    JPA
    코딩 테스트
    SpringDataJpa
    타임리프
    예외 처리
    Java
    백준
    다형성
    스프링 데이터 JPA
    spring
    LocalDateTime
    컬렉션
    BFS
    fetch join
    SOLID
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
0kingki_
[스프링] 싱글톤과 스프링 컨테이너에 대하여
상단으로

티스토리툴바