IoC
IoC란

국제 올림픽 위원회
가 아니라

Inversion of Control의 약자로 "제어 반전"이라는 뜻을 가집니다. 이게 도대체 무슨 소리일까요?
이 단어 앞에 몇글자만 추가된다면 어느정도 알 수 있으실거라고 생각합니다.
"IoC란 개발자와 프레임워크간 제어 반전" 즉 개발자가 제어해야 할 요소들을
Spring Framework에서 대신 제어해준다는 뜻입니다.
원래는 개발자가 직접 객체를 만들고, 필요한 의존 객체도 직접 넣어야 합니다.
IoC는 이러한 주도권을 개발자가 아니라 Spring과 같은 프레임워크가 가져가게 된다는 개념입니다.
즉, 원래는 어떤 객체를 생성할지, 어떤 의존성을 주입할지에 대한 것을 개발자가 직접 정했지만,
객체 생성과 초기화, 소멸, 의존성 관리 등 전반적인 객체의 생명주기 관리를
Spring이 알아서 해주는 것이 이번 블로그에 알아볼 IoC 방식 입니다.
예를 들어서 IoC를 사용하지 않는 일반적인 방식에서는
내가 도시락이 먹고싶으면 직접 재료를 사고, 요리하고, 도시락을 싸서 먹게됩니다.
이러한 방식은 모든 것을 내가 직접 제어하는 방식입니다
하지만 IoC 방식을 사용하게 되면
내가 도시락이 먹고 싶을 때, 배달 앱을 켜서 주문만 하면 알아서 도시락이 만들어진 후
문 앞으로 배달되게 됩니다. 이걸 나는 그냥 꺼내서 먹기만 하면 됩니다.
이처럼 도시락을 만드는 과정은 프레임워크가 대신 해주고
나는 요청만 하고 결과를 받는 방식이 IoC 입니다.
개발로 들어가면 개발자는 필요한 객체를 직접 만들지 않습니다.
대신 Spring 프레임워크가 알아서 객체를 만들고 필요한 곳에 알아서 주입 해줍니다.
IoC의 중요성
그렇다면 IoC가 어떤점에서 중요할까요?
우선 유지보수가 용이합니다. 객체간의 결합도가 낮아서 수정이 쉽습니다.
또한 의존 객체를 테스트용으로 쉽게 교체할 수 있습니다.
기능 변경 시에 객체를 생성하는 로직을 수정할 필요가 없어져서 코드가 유연해 집니다.
그리고 객체 생성, 주입을 자동으로 처리하므로 개발자는 비즈니스 로직에 집중 할 수 있어서
생산성이 향상된다는 등의 장점이 있습니다.
예시 코드로 설명하면
public class Car {
private Engine engine;
public Car() {
this.engine = new Engine();
}
}
이 코드는 IoC 없이 직접 객체를 생성하는 방식입니다.
Car 클래스는 내부적으로 Engine 객체를 직접적으로 생성하고 있습니다.
즉 Car는 Engine이 어떻게 만들어지는지도 알고 있어야 하고, 스스로 책임지고 생성해야 합니다.
이런 방식을 사용하면 Car는 오직 new Engine()을 사용할 수밖에 없어서 결합성이 강해집니다.
또한 Engine 생성 방식이 바뀌면 Car 클래스도 같이 바꿔야 합니다.
그리고 Car를 테스트 하려면 Engine도 항상 같이 따라와야 한다는 등의 문제점이 생기게 됩니다.
그렇다면 이러한 문제점을 해결하기 위해 IoC 방식을 사용하는 코드를 보겠습니다.
@Component
public class Car {
private final Engine engine;
@Autowired
public Car(Engine engine) {
this.engine = engine;
}
}
위 코드는 IoC를 적용해서 Spring을 통한 객체를 주입하는 방식입니다.
@Component 어노테이션은 간단하게 말하자면 Spring에게 "이 클래스 너가 알아서 해줘" 라고 맡기는 역할을 합니다.
@Autowired 어노테이션은 Spring에게 "Car를 만들 때 Engine 객체를 자동으로 찾아서 넣어줘"라고 알려주는 역할을 합니다.
이로인해 new Engine()을 할 필요없이 Spring이 알아서 Engine 객체를 찾고 Car안에 넣어주게 됩니다.
IoC와 DI
IoC는 제어의 주도권은 프레임워크에 넘기는것 이라고 설명했습니다. 그렇다면 프레임워크가 어떻게
어떤 방법으로 제어를 대신하게 될까요? 그 방법 중 하나가 이전 블로그에서 설명한 DI 입니다.
이 둘은 아주 높은 연관성을 가지고 있습니다.
IoC는 제어권을 프레임워크가 가져가는 설계 원칙이고 DI는 이러한 설계 원칙을 구현하는 방식 입니다.
이 두 개념은 스프링에서 핵심적인 철학이라 볼수 있고, 객체지향 프로그래밍의 유연성과
유지보수성을 극대화 시킬 수 있습니다.
즉 스프링에서는 DI를 통해서 IoC를 구현합니다.
하지만 작은 프로젝트에서 과도하게 사용하면 불필요한 복잡성을 유발할 수 있기에
상황에 맞게 알잘딱 해야합니다.
예시 코드로 DI가 사용된 예시를 보겠습니다.
public class Car {
private Engine engine = new Engine();
위 코드는 DI가 없는 경우의 코드입니다.
Car가 직접 Engine을 생성하는걸 볼수 있습니다.
public class Car {
private final Engine engine;
@Autowired
public Car(Engine engine) {
this.engine = engine;
}
}
위 코드는 DI가 적용되어 있는 코드입니다.
@Autowired을 사용해서 스프링이 Engine 객체를 주입하게 되는걸 볼수 있습니다.
마무리
IoC는 애플리케이션 개발에서 객체의 생성주기 관리와 의존성 주입 같은
제어권을 개발자가 아닌 Spring 같은 프레임워크가 담당하는 설계 원칙을 말합니다.
원래는 개발자가 어떤 객체를 만들고, 필요한 의존성을 직접 주입했지만
IoC에서는 이 모든 과정을 프레임워크가 대신 처리하게 됩니다.
이런 방식을 사용하면 코드의 결합도가 낮아지고, 유지보수와 테스트가 용이해지게 됩니다.
또한 개발자가 핵심 로직에 집중할 수 있기 때문에 생산성이 높아집니다.
IoC는 하나의 설계 원칙이고 이를 구현하는 방법 중 하나가 DI입니다.
저는 IoC가 개발을 보다 쉽고 편리하게 하기 위해서 Spring을 공부하며
꼭 알아야하는 개념이라고 생각합니다.
이상으로 블로그를 마치겠습니다. 읽어주셔서 감사합니다.
'Spring' 카테고리의 다른 글
| [Spring] Servlet과 DispatacherServlet (2) | 2025.08.01 |
|---|---|
| [Spring] Spring Filter란? (2) | 2025.08.01 |
| [Spring] PSA란? (0) | 2025.07.22 |
| [Spring] DI란? (0) | 2025.07.16 |
| [Spring] 어노테이션과 import는 무엇일까? (1) | 2025.06.09 |