백엔드 면접 용어 사전
Spring·JPAsingleton scope · 싱글톤

싱글톤 스코프

컨테이너당 빈 인스턴스를 하나만 두는 기본 스코프. 상태를 두면 스레드 안전 문제가 생긴다.

스프링 빈의 기본 스코프. 컨테이너당 인스턴스를 하나만 만들어 공유한다.

왜 기본이 싱글톤인가

요청이 초당 1000건 들어온다고 하자

프로토타입(매번 생성): 초당 1000개의 서비스 객체 생성 → GC 부담

  • 싱글톤: — 1개를 공유 → 생성 비용 0

대부분의 스프링 빈(서비스, 리포지터리)은 상태가 없고 로직만 있으므로 공유해도 아무 문제가 없다. 하나만 만드는 것이 합리적이다.

싱글톤 패턴과 다른 점

// 전통적 싱글톤 패턴
public class Singleton {
    private static final Singleton INSTANCE = new Singleton();
    private Singleton() { }                        // 생성자 막기
    public static Singleton getInstance() { … }
}

문제가 많다 — 상속 불가, 테스트 시 교체 불가, 구체 클래스에 의존 (Singleton.getInstance() 를 호출하는 쪽이 결합된다).

스프링 싱글톤은 "컨테이너가 하나만 만들어 관리"할 뿐, 클래스 자체는 평범하다. 그래서 테스트에서는 그냥 new 해서 쓸 수 있고, 인터페이스 기반 설계도 그대로 가능하다.

가장 중요한 주의점 — 무상태로 설계해야 한다

@Service
public class BadService {
    private int count;                  // ✗ 공유 필드!

    public void process(Order o) {
        count++;                        // 여러 스레드가 동시에 건드린다
        this.currentOrder = o;          // ✗ 스레드 A의 값을 B가 덮어쓴다
    }
}

싱글톤은 모든 요청 스레드가 같은 인스턴스를 쓴다. 필드에 요청별 데이터를 담으면 다른 사용자의 데이터가 섞인다. 실제 서비스에서 "가끔 남의 정보가 보인다"는 사고의 전형적 원인이다.

✅ 지역 변수 사용 (스레드마다 스택이 따로)
✅ 파라미터로 전달
✅ 꼭 필요하면 ThreadLocal (단, 반드시 remove())

읽기 전용 필드는 괜찮다 — 설정값, 다른 빈에 대한 참조는 안전하다.

다른 스코프

스코프생명주기
singleton컨테이너와 함께 (기본)
prototype요청할 때마다 새로 생성. 이후 관리 안 함
requestHTTP 요청마다
sessionHTTP 세션마다
application서블릿 컨텍스트마다

프로토타입의 함정 — 컨테이너는 생성해서 주기만 하고 소멸 콜백(@PreDestroy)을 호출하지 않는다. 자원 정리는 클라이언트 책임이다.

싱글톤이 프로토타입을 주입받으면 — 고전적 문제

@Component
public class SingletonBean {
    @Autowired private PrototypeBean prototype;   // 주입은 딱 한 번!
}

싱글톤이 만들어질 때 프로토타입도 한 번만 주입된다. 이후 계속 같은 인스턴스를 쓰게 되어 프로토타입의 의미가 사라진다.

해결

@Autowired private ObjectProvider<PrototypeBean> provider;
// 쓸 때마다 provider.getObject() → 새 인스턴스

// 또는
@Scope(value = "prototype", proxyMode = TARGET_CLASS)

기동 시점 — 즉시 생성

싱글톤 빈은 애플리케이션 기동 시 전부 생성된다(eager). 그래서 설정 오류나 순환 참조가 기동 단계에서 드러난다. 런타임에 터지는 것보다 훨씬 낫다.

지연 생성이 필요하면 @Lazy를 쓰지만, 기동 시 검증을 포기하는 것이므로 꼭 필요할 때만 쓴다.

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — Spring·JPA — IoC/DI·AOP·영속성 컨텍스트·N+1