백엔드

[Spring Boot] Spring IoC - 개념

빡성 2025. 10. 11. 17:28

Spring IoC 한 줄 소개

IoC(Inversion of Control)는 객체의 생성과 연결, 실행 흐름의 제어권을 프레임워크가 맡고, 애플리케이션 코드는 규칙에 맞춰 정의만 하는 방식이다.

순수 Java 방식과 한계

예시: 직접 생성/호출(강결합)
public class Main {
  public static void main(String[] args) throws Exception {
    Steps steps = new Communication();
    steps.initialize();
    steps.process();
    steps.destroy();
  }
}

public class Communication implements Steps {
  private final Greeting greeting;
  private final Farewell farewell;
  private final Sender sender;

  public Communication() {
    this.greeting = new EnglishGreeting();
    this.farewell = new EnglishFarewell();
    this.sender = new ConsoleSender();
  }

  public void initialize() { greeting.sayHello(); }

  public void process() {
    Request req = new Request("sando", "hello");
    sender.sendMessage(req);
  }

  public void destroy() { farewell.sayGoodBye(); }
}
문제점
  • 실행 순서 호출을 개발자가 직접 관리 → 누락/순서 실수 위험.
  • 여러 곳에서 같은 객체를 직접 생성 → 중복 초기화/강결합.
  • 교체(English→Korean 등) 시 사용처 코드를 수정해야 함.
  • 객체 초기화 시점이 제각각 → 일관성/가시성 저하.
  • 테스트가 어려움(의존 객체 전부 준비 필요).

IoC(제어 역전)란?

제어권을 프레임워크에 넘기고, 코드는 규칙에 맞춰 역할을 선언한다. 프레임워크가 객체를 생성·연결하고 정해진 생명주기(초기화→처리→정리)에 따라 필요한 시점에 애플리케이션 코드를 호출한다.

가상의 IoC 프레임워크 예시

예시: “정의만 하고, 호출은 프레임워크가”
// (가정) 프레임워크 규칙: Steps 구현체를 찾아 initialize → process → destroy 순서로 실행
// @Part 붙은 타입은 프레임워크가 기본 생성자로 객체를 만들고 주입한다고 가정

// 사용자 코드
@Part class EnglishGreeting implements Greeting { public void sayHello(){ System.out.println("hello"); } }
@Part class EnglishFarewell implements Farewell { public void sayGoodBye(){ System.out.println("bye"); } }
@Part class ConsoleSender implements Sender { public void sendMessage(Request r){ System.out.println(r.message()); } }

class Communication implements Steps {
  @Part Greeting greeting;
  @Part Farewell farewell;
  @Part Sender sender;

  public void initialize(){ greeting.sayHello(); }
  public void process(){ sender.sendMessage(new Request("sando","hello")); }
  public void destroy(){ farewell.sayGoodBye(); }
}

// 프레임워크 내부(개발자가 작성 X)
class FrameworkMain {
  public static void main(String[] args){
    Steps s = Factory.create(Steps.class); // @Part 보고 생성·주입
    s.initialize(); s.process(); s.destroy(); // 규칙대로 호출
  }
}
정리
  • 흐름 제어·객체 생성/연결을 프레임워크가 담당 → 실수 감소, 일관성 확보.
  • 구현 교체가 쉬움(정의만 바꾸면 호출부 수정 최소화).
  • 테스트 시 대역(Stub/Mock) 주입이 용이.