TIL/내일배움캠프

[Spring] IoC와 DI — 좋은 코드의 핵심 원칙

bu119 2025. 9. 22. 22:00
728x90
반응형

📝 TIL (Today I Learned) — 2025.09.22. 월요일

✍️ 내일배움캠프에서 Spring 학습 중 정리한 내용입니다.

1. IoC와 DI란?

Spring을 배우면 가장 먼저 접하는 단어가 IoCDI입니다.
많은 분들이 “Spring에서만 쓰는 기능”으로 오해하지만, 사실은 객체지향 설계 원칙에서 비롯된 개념입니다.

  • IoC (Inversion of Control, 제어의 역전)
    객체 생성과 제어 권한을 개발자가 아닌 외부(Spring IoC 컨테이너)에 맡기는 개념
    → Spring IoC 컨테이너가 객체 생성, 의존성 연결, 생명주기 관리까지 담당합니다.
    👉 “내가 직접 만들지 말고, 대신 해줄 사람에게 맡기자”
  • DI (Dependency Injection, 의존성 주입)
    IoC 원칙을 구현하는 대표적인 방법
    객체가 필요한 다른 객체를 직접 생성하지 않고, 외부에서 주입받아 사용합니다.
    👉 “필요한 걸 외부에서 갖다 넣어주자”

즉, IoC큰 설계 개념이고, DI는 이를 구현하는 방법입니다.


2. 왜 필요한가?

좋은 코드는

  • 중복이 적고,
  • 이해하기 쉽고,
  • 유지보수가 편리하며,
  • 다른 코드와의 결합도가 낮아야 합니다.

IoC와 DI는 이 중 결합도를 낮추는 핵심 기술입니다.


3. 의존성과 결합도

의존성이란 “A가 B 없이는 동작할 수 없는 상태”를 의미합니다.

 

아래 코드를 보면, Consumer는 Chicken에 강하게 의존합니다.

public class Consumer {
    void eat() {
        Chicken chicken = new Chicken();
        chicken.eat();
    }
}

 

👉 문제점

  • Consumer는 무조건 Chicken만 먹습니다.
  • 만약 피자를 먹고 싶다면 Consumer 코드를 수정해야 합니다.
  • 즉, 코드가 특정 클래스(Chicken)에 강하게 결합되어 있습니다.

4. 결합도 낮추기 → 인터페이스 도입 

이를 해결하려면 구체적인 클래스가 아니라 추상적인 개념(인터페이스)에 의존하도록 바꿔야 합니다.
Chicken, Pizza 같은 개별 음식 대신, 음식(Food)이라는 공통 인터페이스를 정의하는 방식입니다.

interface Food { void eat(); }

class Chicken implements Food {
    public void eat() { System.out.println("치킨을 먹는다."); }
}
class Pizza implements Food {
    public void eat() { System.out.println("피자를 먹는다."); }
}

public class Consumer {
    void eat(Food food) {
        food.eat();
    }
}

이제 Consumer는 Food라는 추상화에만 의존합니다.
👉 Chicken이든 Pizza든 자유롭게 교체 가능하며, 새로운 음식 클래스를 추가해도 Consumer 코드를 수정할 필요가 없습니다.

 

결과

  • 결합도 ↓
  • 유연성 ↑
  • 유지보수성 ↑

5. 주입(Injection)의 방법

외부에서 필요한 객체를 넣어주는 걸 주입(Injection)이라고 합니다.

 

  • 필드 주입 (실무에서는 권장되지 않음)
consumer.food = new Chicken();

편리해 보이지만 테스트가 어렵고 순환 참조 문제도 발생하기 때문에 실무에서 거의 사용되지 않습니다.

 

  • Setter 주입
consumer.setFood(new Pizza());

선택적으로 교체 가능하지만, 객체가 불변하지 않게 됩니다.

 

  • 생성자 주입 (Spring 권장 방식)
Consumer consumer = new Consumer(new Chicken());

불변성 보장 + 테스트 용이성 확보 → Spring에서 가장 권장되는 주입 방법입니다.


6. 제어의 역전(IoC)

원래는 Consumer가 직접 Chicken을 생성했지만,
이제는 외부에서 만들어진 객체(Food)를 주입받아 사용합니다.

 

즉, 객체 제어 흐름이

  • 예전: Consumer → Food (내가 직접 만든다)
  • 지금: Spring IoC 컨테이너 → Consumer (외부가 대신 넣어준다)

👉 이것이 바로 제어의 역전(IoC)입니다.


✨ 정리

  • IoC = 객체 생성·관리 책임을 개발자가 아닌 Spring IoC 컨테이너에 위임
  • DI = IoC를 실현하는 대표적인 방법, 필요한 객체를 외부에서 주입받음
  • Spring 권장 주입 방식 = 생성자 주입
  • 효과 = 결합도 ↓, 확장성 ↑, 유지보수성 ↑

Spring은 IoC와 DI를 기반으로, 개발자가 객체 생성이 아닌 비즈니스 로직에 집중할 수 있도록 돕습니다.

728x90
반응형