
왜 스프링은 기본이 싱글톤일까? (그리고 @Configuration의 진짜 역할)
이 챕터는 단순히 “싱글톤이 좋다”가 아니라
웹 환경에서 왜 싱글톤이 기본 전략인지를 이해하는 파트였다.
그리고 마지막에 나오는 CGLIB 이야기가 은근히 재밌다.
스프링은 기본적으로 웹 애플리케이션을 위한 기술에서 출발했다.
웹 환경의 특징은 이거다.
동시에 여러 사용자가 요청을 보낸다.
만약 우리가 만들었던 순수 DI 컨테이너(AppConfig)가
요청 올 때마다 객체를 새로 만든다면?
이건 그냥 메모리 낭비다.
그래서 해결 방법은 단순하다.
“객체를 한 번만 만들고, 공유하면 되지 않나?”
그게 바로 싱글톤이다.
싱글톤 패턴은
“객체를 딱 1개만 생성하도록 보장하는 디자인 패턴”
전통적인 방식은 이런 느낌이다.
public class SingletonService {
private static final SingletonService instance = new SingletonService();
private SingletonService() {}
public static SingletonService getInstance() {
return instance;
}
}
근데 문제 많다
강의에서 강조한 단점이 꽤 많다.
결론적으로 좋은 객체지향 설계랑 안 맞는다.
그래서 이걸 직접 쓰는 건 점점 안티패턴 취급을 받는다.
스프링은 다르게 접근한다.
“패턴을 직접 쓰지 말고, 컨테이너가 대신 관리해줄게.”
스프링 컨테이너는
이걸 싱글톤 레지스트리라고 한다.
그리고 우리가 지금까지 만든 @Bean 객체들은
기본적으로 전부 싱글톤이다.
여기서 중요한 차이:
이게 스프링이 잘 설계된 부분이라고 느꼈다.
싱글톤은 객체를 공유한다.
즉,
여러 사용자가 하나의 객체를 동시에 사용한다.
그래서 절대 하면 안 되는 게 있다.
상태를 가지면 안 된다 (stateful 금지)
예를 들어 이런 코드가 있다면
private int price; // 공유 필드
ThreadA가 10000원 넣고
ThreadB가 20000원 넣으면
결과가 꼬일 수 있다.
사용자A 주문금액이
20000원으로 나올 수도 있다.
⸻
그래서 원칙은 이거다.
스프링 빈은 무조건 “무상태(stateless)“로 설계하자.
이건 실무에서도 진짜 중요하다고 느껴진다.
이 파트가 제일 흥미로웠다.
AppConfig 코드에서 이런 상황이 있었다.
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
겉으로 보면 memberRepository()가
• 컨테이너 등록할 때 1번
• memberService에서 1번
• orderService에서 1번
총 3번 호출될 것 같지 않나?
그럼 MemoryMemberRepository 인스턴스도 3개 생겨야 맞다.
근데 실제로는 1개만 생성된다.
왜?
비밀은 여기에 있다.
@Configuration
public class AppConfig { ... }
스프링은 @Configuration이 붙은 클래스를 그냥 쓰지 않는다.
CGLIB라는 바이트코드 조작 라이브러리를 사용해서
AppConfig를 상속한 가짜 클래스를 하나 만든다.
예를 들어 클래스 이름이 이런 식으로 바뀐다.
AppConfig$$EnhancerBySpringCGLIB
이 가짜 클래스 안에서 이런 동작을 한다.
@Bean 메서드를 호출하면
이미 빈이 존재하는지 확인하고
있으면 기존 빈 반환
없으면 생성해서 등록 후 반환
그래서 결과적으로 싱글톤이 보장된다.
여기서 중요한 포인트.
@Configuration을 빼고
@Bean만 쓰면?
→ CGLIB이 동작하지 않는다.
→ memberRepository()가 실제로 여러 번 호출된다.
→ 인스턴스가 여러 개 생성된다.
즉, @Bean만으로는 싱글톤을 보장하지 않는다.
그래서 실무에서는
스프링 설정 클래스에는 무조건 @Configuration을 붙인다.
라고 이해하면 된다.
스프링은 “싱글톤 패턴을 쓰는 게 아니라”
싱글톤을 안전하게 관리해주는 컨테이너다.
그리고 @Configuration은
그 싱글톤을 보장하는 숨은 핵심 장치다.
출처
스프링 핵심 원리 - 기본편 (김영한, 인프런, 2020)