[Spring] 03. IoC란?

[Spring] 03. IoC란?

이전 글에서는 Spring Framework가 무엇인지 살펴봤습니다. Spring은 Java 애플리케이션을 더 체계적으로 만들기 위한 프레임워크이고, 객체 관리와 계층 분리를 도와줍니다.

이번 글에서는 Spring의 핵심 개념 중 하나인 IoC에 대해 정리해보겠습니다. IoC는 처음 보면 어려운 단어처럼 느껴지지만, 핵심은 단순합니다.

IoC는 객체를 개발자가 직접 만들고 관리하는 것이 아니라, Spring이 대신 관리하도록 맡기는 개념입니다.


1. IoC란?

IoC는 Inversion of Control의 줄임말입니다. 한국어로는 제어의 역전이라고 부릅니다.

여기서 제어란 객체를 생성하고, 필요한 곳에 연결하고, 사용하는 흐름을 말합니다. 일반적인 Java 코드에서는 개발자가 직접 객체를 생성하고 사용합니다.

BoardService boardService = new BoardService();

이 코드는 BoardService 객체를 개발자가 직접 생성한 예시입니다. 필요한 객체가 있으면 직접 만들고, 직접 연결해서 사용합니다.

하지만 Spring에서는 객체를 개발자가 직접 만들지 않고, Spring이 객체를 생성하고 관리할 수 있습니다. 즉, 객체 관리의 주도권이 개발자 코드에서 Spring으로 넘어갑니다. 이 흐름을 IoC라고 합니다.


2. 제어가 역전된다는 말의 의미

제어의 역전이라는 표현은 조금 딱딱하게 느껴질 수 있습니다. 쉽게 말하면, 객체를 누가 관리하느냐가 바뀐다는 뜻입니다.

일반 Java 방식 개발자가 직접 객체를 생성하고 연결합니다.
Spring 방식 Spring이 객체를 생성하고 필요한 곳에 연결합니다.

예를 들어 게시글 기능을 만든다고 생각해보겠습니다. Controller는 Service를 사용하고, Service는 Mapper를 사용합니다.

BoardController
 → BoardService
 → BoardMapper

일반 Java 방식이라면 Controller 안에서 Service 객체를 직접 만들 수 있습니다.

public class BoardController {

    private BoardService boardService = new BoardService();

}

이 방식은 처음에는 단순해 보입니다. 하지만 기능이 많아질수록 객체끼리 강하게 묶이게 됩니다. BoardService를 바꾸거나 테스트하려고 할 때 Controller 코드까지 영향을 받을 수 있습니다.

Spring 방식에서는 Controller가 Service를 직접 만들지 않습니다. 필요한 객체를 Spring이 연결해줍니다.

@Controller
public class BoardController {

    private final BoardService boardService;

    public BoardController(BoardService boardService) {
        this.boardService = boardService;
    }
}

여기서는 BoardController가 BoardService를 직접 생성하지 않습니다. 생성자를 통해 필요한 객체를 전달받습니다. 이 객체를 준비하고 연결하는 일은 Spring이 담당합니다.


3. 왜 IoC가 필요할까?

IoC가 필요한 이유는 코드의 의존성을 줄이고, 유지보수하기 좋은 구조를 만들기 위해서입니다.

객체를 직접 생성하는 코드가 많아지면 변경에 약해집니다. 하나의 클래스가 다른 클래스를 직접 만들고 있으면, 서로 강하게 연결됩니다. 이런 구조에서는 기능을 바꾸거나 테스트할 때 불편함이 생깁니다.

private BoardService boardService = new BoardService();

위 코드처럼 직접 객체를 생성하면 BoardController는 BoardService 구현에 강하게 묶입니다. 다른 Service로 바꾸고 싶어도 Controller 코드를 수정해야 합니다.

반대로 Spring이 객체를 관리하면 Controller는 필요한 객체를 전달받아 사용하면 됩니다. 객체를 어떻게 만들고 연결할지는 Spring이 처리합니다.

이렇게 하면 각 클래스는 자기 역할에 더 집중할 수 있습니다. Controller는 요청 처리에 집중하고, Service는 기능 흐름에 집중하고, Mapper는 DB 접근에 집중할 수 있습니다.


4. IoC와 Spring Container

Spring에서 객체를 생성하고 관리하는 공간을 Spring Container라고 부릅니다. Spring Container는 애플리케이션에서 필요한 객체를 만들고 보관합니다.

Spring이 관리하는 객체를 Bean이라고 합니다. 즉, Spring Container 안에 등록되어 관리되는 객체가 Bean입니다.

Spring Container
 ├─ BoardController
 ├─ BoardService
 └─ BoardMapper

개발자가 직접 new로 객체를 만드는 대신, Spring Container가 객체를 관리합니다. 그리고 필요한 곳에 객체를 연결해줍니다.

그래서 IoC를 이해할 때는 다음 흐름을 기억하면 됩니다.

객체 생성
 → 객체 보관
 → 필요한 곳에 연결
 → Spring이 관리

5. IoC와 DI의 관계

IoC를 공부하면 DI라는 개념도 함께 나옵니다. DI는 Dependency Injection의 줄임말이고, 한국어로는 의존성 주입이라고 부릅니다.

IoC는 객체 관리의 주도권이 Spring으로 넘어가는 큰 개념입니다. DI는 그 과정에서 필요한 객체를 외부에서 넣어주는 방법입니다.

IoC 객체 관리의 흐름을 Spring이 가져가는 개념
DI 필요한 객체를 외부에서 넣어주는 방식

즉, DI는 IoC를 구현하는 대표적인 방법입니다. Spring에서는 DI를 통해 객체를 필요한 곳에 연결합니다.

public BoardController(BoardService boardService) {
    this.boardService = boardService;
}

위 코드에서 BoardController는 BoardService를 직접 만들지 않습니다. 외부에서 전달받습니다. 이런 방식이 의존성 주입입니다.


6. IoC를 사용하면 좋은 점

IoC를 사용하면 객체 생성과 연결을 Spring이 관리하기 때문에 코드 구조가 정리됩니다. 클래스마다 자기 역할에 집중할 수 있고, 변경에도 더 유연해집니다.

  • 객체 생성 코드가 줄어듭니다.
  • 클래스 간 결합이 약해집니다.
  • 역할을 나누기 쉬워집니다.
  • 테스트하기 좋은 구조가 됩니다.
  • 기능이 커져도 관리하기 쉬워집니다.

게시판 프로젝트를 예로 들면, 게시글 등록 로직이 바뀌어도 Controller 전체를 크게 수정할 필요가 줄어듭니다. Service의 역할만 잘 나누면 기능별 흐름을 더 쉽게 관리할 수 있습니다.


정리

IoC는 Inversion of Control의 줄임말이며, 제어의 역전이라고 부릅니다. 핵심은 객체를 개발자가 직접 생성하고 관리하는 것이 아니라, Spring이 대신 생성하고 관리한다는 점입니다.

일반 Java 코드에서는 필요한 객체를 직접 new로 생성합니다. 하지만 Spring에서는 Spring Container가 객체를 만들고, 필요한 곳에 연결해줍니다. 이렇게 Spring이 관리하는 객체를 Bean이라고 합니다.

IoC를 이해하면 DI, Bean, Container 같은 Spring 핵심 개념을 더 쉽게 이해할 수 있습니다. 다음 글에서는 IoC와 함께 자주 등장하는 DI가 무엇인지 정리해보겠습니다.