프로그래밍/C#

[C#] Singleton, Scoped, Transient 차이점 – DI Container 생명주기 완전 정리

큐레이트 2025. 3. 24. 11:00

[C#] Singleton, Scoped, Transient 차이점 – DI Container 생명주기 완전 정리

C#에서 의존성 주입(Dependency Injection)을 사용할 때, DI Container에 등록할 수 있는 Singleton, Scoped, Transient는 각기 다른 생명주기를 가지고 있습니다.

실무에서 자주 쓰이는 이 3가지 생명주기의 차이점사용 시 주의할 점, 그리고 예제를 통한 설명을 함께 정리해보겠습니다.


🔁 1. Singleton – 앱 전체에서 단 하나

Singleton으로 등록된 서비스는 애플리케이션 실행 동안 딱 1개 인스턴스만 생성되어, 모든 곳에서 공유됩니다.


// 등록 방법
services.AddSingleton<IMyService, MyService>();
  • 처음 요청 시 1회 생성 → 이후 모든 요청에서 동일한 인스턴스 반환
  • 상태를 유지해야 하는 캐시, 설정, Logger 등에 적합

주의: 상태 공유 때문에 Thread-Safe하게 설계되어야 합니다.


🧩 2. Scoped – 요청(Request)당 하나

Scoped로 등록된 서비스는 HTTP 요청마다 새 인스턴스가 생성됩니다.
ASP.NET Core에서는 컨트롤러 단위로 공유되며, 동일 요청 안에서는 하나의 인스턴스가 사용됩니다.


// 등록 방법
services.AddScoped<IMyService, MyService>();
  • 웹 요청마다 새로운 인스턴스 생성
  • DBContext, 사용자 요청 데이터 처리에 적합

주의: 콘솔 앱이나 WinForms에서는 별도 Scope 관리가 필요합니다.


⚡ 3. Transient – 요청마다 새로 생성

Transient는 요청될 때마다 항상 새로운 인스턴스를 생성합니다.
의존 객체까지 전부 새로 만들어지기 때문에 가볍고 독립적인 서비스에 적합합니다.


// 등록 방법
services.AddTransient<IMyService, MyService>();
  • 요청마다 새 인스턴스 생성 (심지어 같은 요청에서도 여러 번 생성 가능)
  • 상태를 가지지 않는 Helper 클래스, 계산기, 포맷터 등에 적합

🔍 생명주기 비교 표

종류 인스턴스 수명 적합한 용도
Singleton 앱 전체에서 1개 설정, 캐시, 공통 서비스
Scoped 요청(Request)당 1개 DBContext, 사용자 세션
Transient 요청마다 새로 Helper, Utility, Stateless 서비스

🧠 실무 팁 – 언제 어떤 생명주기를 써야 할까?

  • Singleton – 상태를 공유해도 문제가 없는 서비스 (예: 로깅, 캐시)
  • Scoped – 요청 기반의 리소스를 다룰 때 (예: DbContext)
  • Transient – 가벼운 서비스, 상태가 없는 도구성 클래스

잘못된 생명주기를 적용하면 의도하지 않은 상태 공유메모리 낭비가 발생할 수 있습니다.
따라서 서비스의 역할과 범위에 따라 생명주기를 신중하게 선택해야 합니다.


📌 마무리

의존성 주입(DI)은 유지보수성과 테스트 용이성을 높여주는 핵심 기술입니다.
그만큼 생명주기를 제대로 이해하고 사용하는 것이 중요합니다.

이 글이 도움이 되셨다면 공감 / 댓글 부탁드립니다 😊

반응형