> For the complete documentation index, see [llms.txt](https://dodeon.gitbook.io/study/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://dodeon.gitbook.io/study/kimyounghan-spring-core-principle/03-oop/ioc-di-container.md).

# IoC, DI, 컨테이너

## 제어의 역전

개발자가 호출하는 게 아니라 프레임워크 등이 대신 호출해주는 것이다. 스프링에만 국한된 개념은 아니다.

기존 프로그램은 클라이언트 구현 객체가 스스로 필요한 객체를 생성하고 연결하고 실행했다. 구현 객체가 프로그램의 제어 흐름을 스스로 조종했다.

반면 `AppConfig` 등장 이후엔 구현 객체는 자신의 로직을 실행하는 역할만 담당한다. 서비스 구현 객체만 봐서는 어떤 저장소가 어떤 객체로 호출될지를 모르는 것이다.

```java
public class AppConfig {

  public OrderService orderService() {
    return new OrderServiceImpl(memberRepository(), discountPolicy());
  }
}
```

프로그램 제어 흐름은 `AppConfig`가 모두 가진다. 클라이언트 구현 객체인 `OrderServiceImpl`도 이제 `AppConfig`가 쓸지 말지를 결정한다. `OrderServiceImpl`가 아닌 다른 구현 객체를 실행할 수도 있는 것이다. `OrderServiceImpl`은 그런 사실도 모른 채 묵묵히 자신의 로직을 실행할 뿐이다.

이렇게 프로그램의 흐름을 직접 제어하지 않고 외부에서 관리하는 것을 제어의 역전이라고 한다.

### 프레임워크

* 내가 작성한 코드를 제어하고 대신 실행하는 것
* ex) `JUnit`은 내가 작성한 테스트 코드를 직접 실행해준다.

### 라이브러리

* 내가 작성한 코드가 직접 제어의 흐름을 담당하는 것
  * 직접 메인 메서드에 넣거나 new 해서 생성하는 것
* ex) `Jackson`을 이용해 JSON을 오브젝트로 바꾼다.

## 의존 관계 주입

`OrderServiceImpl`은 `DiscountPolicy` 인터페이스에 의존한다. 실제 어떤 구현 객체가 사용될지는 모른다.

그래서 의존 관계는 `정적인 클래스 의존 관계`와 `실행 시점에 결정되는 동적인 객체(인스턴스)의 의존 관계`를 분리해서 생각해야 한다.

### 정적인 클래스 의존 관계

클래스가 사용하는 import 코드만 보고 의존 관계를 쉽게 판단할 수 있다. 정적인 의존 관계는 애플리케이션을 실행하지 않아도 분석할 수 있다.

![](https://389280719-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LxjHkZu4T9MzJ5fEMNe%2Fsync%2F25338503ae8c785736385aa6d65323a0532acb1c.png?generation=1618026421401103\&alt=media)

다이어그램을 보면 `OrderServiceImpl`은 `MemberRepository`, `DiscountPolicy`에 의존한다. 그런데 이 클래스 의존관계 만으로는 실제 어떤 객체가 `OrderServiceImpl`에 주입될 지 알 수 없다.

### 동적인 객체 인스턴스 의존 관계

애플리케이션 실행 시점에 실제 생성된 객체 인스턴스 참조가 연결된 의존 관계다.

![](https://389280719-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LxjHkZu4T9MzJ5fEMNe%2Fsync%2F7a430eb670189d9f89b9e2913ff5d5ed0cb3ba6f.png?generation=1618026422648097\&alt=media)

애플리케이션 실행 시점(런타임)에 외부에서 실제 구현 객체를 행성하고 클라이언트에 전달하면, 클라이언트와 서버의 실제 의존 관계가 연결되는 것을 의존 관계 주입이라고 한다. 객체 인스턴스를 생성하고 그 참조 값을 전달해서 연결된다.

의존 관계 주입을 사용하면 클라이언트 코드를 변경하지 않고도 클라이언트가 호출하는 타입 인스턴스를 변경할 수 있다. 즉, 정적인 클래스 의존 관계를 변경하지 않고도 동적인 객체 인스턴스 의존 관계를 쉽게 변경할 수 있다.

## IoC 컨테이너, DI 컨테이너

`AppConfig`처럼 객체를 생성하고 관리하면서 의존 관계를 연결해 주는 것을 IoC 컨테이너 혹은 DI 컨테이너라고 한다.

의존 관계 주입에 초점을 맞춰 최근에는 주로 DI 컨테이너라고 한다. 어셈블러, 오브젝트 팩토리 등으로 불리기도 한다.
