IoC란 제어의 역전을 말합니다. 풀어서 말하면 프로그램의 흐름에 대한 제어권을 스프링과 같이 외부에서 가져가는 것입니다.
아마 이렇게 처음 글자로만 접하시면 이해가 안될 것입니다.
이해를 위해 다음과 같은 서비스가 있다고 생각해보겠습니다.
public interface Calculator {
...
}
@RequiredArgsConstructor
public class OrderService {
private final Calculator calculator;
public void logic() {
... 관련 로직
}
}
public class FastCalculator implement Calculator { ... }
public class SlowCalculator implement Calculator { ... }
OrderService
는 주문 가격을 계산하기 위해 Calculator
를 사용합니다.
위 서비스를 main함수를 통해 실행시키려면 다음과 같이 코드를 작성할 수 있습니다.
public static void main(String[] args) {
Calculator calculator = new FastCalculator();
OrderService orderService = new OrderService(calculator);
orderService.logic();
}
위와 같이 실행시키면 프로그램에 대한 제어를 개발자가 직접 할 수 있습니다. 만약 FastCalculator
대신 SlowCalculator
라는 구현체를 쓰고 싶다면 개발자가 직접 코드를 바꾸면 됩니다. 이렇게 main
함수 안에서는 개발자의 의도된 흐름대로 제어되며 실행될 것입니다.
그럼 이제 스프링에서 OrderService
를 사용하고 싶을 땐 어떻게 해야 할까요?
다음과 같이 애노테이션을 추가해주어 객체가 스프링 컨테이너에 등록되어 관리되도록 만듭니다.
@Component // 추가
@RequiredArgsConstructor
public class OrderService {
...
}
@Component // 추가
public class FastCalculator implement Calculator{
...
}
그리고 스프링에서는 ApplicationContext
를 통해 OrderService
를 사용할 수 있을 것입니다.
@Autowired
ApplicationContext applicationContext;
public static void main(String[] args) {
OrderService orderService = applicationContext.getBean(OrderService.class);
orderService.logic();
}
이렇게 된다면 FastCalculator
대신 SlowCalculator
라는 구현체를 쓰고 싶어도 해당 main
함수에서 할 수 있는 것이 없습니다.
스프링 컨테이너에 등록되어 의존관계를 주입 받기 때문에 개발자가 제어할 수 없는 것입니다.
프로그램의 제어의 흐름이 외부에 의해 관리되는 것. 이것을 제어의 역전(IoC)이라 말합니다.
= 객체의 생성과 관리를 프레임워크나 컨테이너에 위임하는 것
DI(Dependency Injection)는 의존관계 주입을 의미합니다.
객체 간의 의존 관계를 외부에서 주입하는 방식으로 객체를 생성하고 연결합니다.
계속 '의존관계', '의존'이라고 말하고 있는데 "의존"이 무엇일까요?
어떤 객체도 섬이 아닙니다. 객체들은 특정한 목표(기능 구현)를 이루기 위해 역할과 책임을 가지고 협력에 참여합니다. 즉 객체는 자신의 기능을 수행할 때 다른 객체의 도움이 필요하다는 의미입니다.
앞서 OrderService
와 Calculator
의 관계를 생각해보겠습니다.
OrderService
는 주문 가격을 계산하고 싶다면 Calculator
의 도움이 필요합니다. OrderService
가 주문 가격을 계산하는 기능은 존재하지 않습니다.
이런 경우를 "OrderService
는 Calculator
에 의존한다"고 말합니다.
앞서 본 코드에 applicationContext.getBean(OrderService.class);
를 다시 봐보겠습니다.
@Autowired
ApplicationContext applicationContext;
public static void main(String[] args) {
OrderService orderService = applicationContext.getBean(OrderService.class);
orderService.logic();
}
개발자는 OrderService
를 new
연산자를 통해 만들지 않았습니다. 그러나 외부(스프링 컨테이너)에서 OrderService
가 의존하는 Calculator
를 알아서 연결해 주었습니다.
이렇게 외부에서 알아서 연결해주는 것을 의존관계 주입(DI)이라고 말합니다.
IoC는 DI(Dependency Injection)을 포함하는 개념이기도 하답니다.