[참고] DI(의존성 주입, Dependency Injection)

박은서's avatar
Feb 05, 2026
[참고] DI(의존성 주입, Dependency Injection)

1. DI(의존성 주입, Dependency Injection)

1️⃣ DI(Dependency Injection)

1) 개념

한 객체가 필요로 하는 다른 객체(의존성)를 객체 스스로 생성하지 않고, 외부에서 주입받도록 하는 설계 기법

2) 핵심 아이디어

  • 객체는 무엇을 할지만 알고
  • 어떤 구현체를 쓸지는 외부에서 결정한다
이로써 객체 간 **결합도(coupling)**를 낮추는 것이 목적

2️⃣ DI가 필요한 이유

1) ❌ DI 사용하지 않을 경우

  • 클래스 내부에서 직접 다른 클래스를 생성
  • 구현체에 강하게 의존
  • 변경·테스트가 어려움

2) ⭕ DI 적용

  1. 결합도 감소
      • 구현체 변경 시 수정 범위가 작아짐
  1. 테스트 용이성
      • Mock 객체 주입이 쉬워짐
  1. 유지보수성 향상
      • 기능 확장에 유리
  1. 객체 책임 분리
      • SRP(단일 책임 원칙) 강화

3️⃣ DI의 기본 개념 구조

  • Client: 의존성을 사용하는 객체
  • Dependency: 필요한 기능을 제공하는 객체
  • Injector: 의존성을 생성하여 주입하는 주체
💡
Client는 Dependency의 구체 구현을 모른 채 인터페이스에만 의존하는 것이 이상적

4️⃣ DI의 주요 방식

1) 생성자 주입 (Constructor Injection)

가장 권장되는 방식입니다.
  • 객체 생성 시점에 의존성이 확정
  • 불변성 보장
  • 테스트에 유리

2) 세터 주입 (Setter Injection)

  • 객체 생성 후 의존성 주입
  • 선택적 의존성에 사용
  • 누락 가능성 주의 필요

3) 필드 주입 (Field Injection)

  • 간편하지만
  • 테스트와 추적이 어렵고
  • 일반적으로 권장되지 않음

5️⃣ DI와 IoC의 관계

  • IoC (Inversion of Control): 제어의 역전이라는 개념
  • DI: IoC를 구현하는 구체적인 방법 중 하나
DI ⊂ IoC

6️⃣ 프레임워크에서의 DI

DI는 보통 프레임워크 차원에서 지원됨
  • Spring / Spring Boot (Java)
  • ASP.NET Core (C#)
  • NestJS (TypeScript)
  • Angular
➡️ 이들은 모두 DI Container를 통해 객체 생성과 주입을 관리

7️⃣ 비유로 DI 이해하기 - 예시 1: 햄버거 가게 이야기

❌ DI가 없는 경우

1. 빵 만들기 2. 고기 만들기 3. 치즈 만들기 4. 직접 햄버거 완성
➡️ 너무 힘들어 😵
➡️ 햄버거 말고 만드는 방법에 신경을 써야 함

✅ DI가 있는 경우

1. 빵 주세요 2. 고기 주세요 3. 치즈 주세요 4. 햄버거 완성
누군가가 필요한 재료를 다 가져다 줌
➡️ 나는 햄버거 만드는 일만 하면 됨
➡️ 이게 바로 DI

👩🏻‍🏫Spring은 필요한 물건을 자동으로 챙겨주는 선생님!

Spring: "너 햄버거 만들거지?" "빵, 고기, 치즈 필요하지?" "여기 있어!"
➡️ 우리는 그냥 받아서 쓰기만 하면 됨

8️⃣ final + @RequiredArgsConstructor 조합

“이 물건은 꼭 있어야 하고, 중간에 바뀌면 안 될 때” 사용

1) 비유 : 로봇과 건전지

로봇은 건전지가 없으면 절대 못 움직임
➡️ 이런 건전지는
  • 없으면 안 됨 ❌
  • 중간에 바뀌면 안 됨 ❌
➡️ 이럴 때 쓰는 게 final + @RequiredArgsConstructor

2) 코드

class Robot { private final Battery battery; public Robot(Battery battery) { this.battery = battery; } }
  • 🔒 final → 건전지 바꾸지 마!
  • 🧾 생성자 → 태어날 때 꼭 받아!
➡️ “필수 물건” 표시

3) Spring + Lombok 버전

@RequiredArgsConstructor class Robot { private final Battery battery; }
Spring:
“아~ 배터리 꼭 필요하구나. 내가 태어날 때 넣어줄게!”

4) 언제 쓰면 좋을까?

상황
써야 할까?
없으면 바로 고장
항상 있어야 함
중간에 바뀌면 안 됨
서비스, 컨트롤러
✅ 거의 항상
➡️ 실무의 기본값

9️⃣ @Autowired

“이건 있으면 좋고, 없어도 괜찮을 때”

1) 비유: 가방 속 물건

연필: 꼭 필요함 스티커: 있으면 좋음
스티커 같은 물건 = @Autowired

2) 예시

@Autowired private Sticker sticker;
  • “있으면 써볼게”
  • “없어도 울지 않을게”

3) @Autowired를 쓰는 대표 상황

① 선택 물건일 때
@Autowired(required = false) private Logger logger;
  • 없어도 OK
  • 있으면 더 좋음
② 나중에 바꿀 수도 있을 때
@Autowired public void setBattery(Battery battery) { this.battery = battery; }
  • 중간에 교체 가능
③ 생성자가 여러 개일 때
@Autowired public Robot(Battery battery) {}
Spring에게:
“이 생성자 써!”
Share article