# IoC / DI 에 대해 설명해 주세요.

* `IoC`와 `DI`는 스프링의 핵심 개념 중 하나이다.
* 객체 지향 프로그래밍에서 중요한 **디자인 패턴**으로, 코드의 결합도를 낮추고 유연성을 높일 수 있게 해준다. 왜냐하면 개발자가 직접 의존성 관리를 하는 것보다 효율적으로 할 수 있기 때문이다.

## IoC

* **`IoC`는 Inversion Of Control**의 약자로, **제어의 역전**이라는 뜻을 가지고 있다.
* 뜻 그대로 프로그램의 흐름을 개발자가 아닌 프레임워크가 관리하는 것을 의미한다.
* 객체의 생성과 생명주기 관리를 프레임워크가 담당하게 되어, 개발자는 비즈니스 로직에 더 집중할 수 있다.

## DI

* **`DI`는 Dependency Injection**의 약자로, **의존성 주입**이라는 뜻을 가지고 있다.
* 객체 간의 의존성을 외부에서 주입하는 방식을 말한다.
* **DI를 통해 얻을 수 있는 장점**
  * 개발자는 객체 간의 결합도를 낮추고, 코드의 유연성을 높일 수 있다.
    * `DI`를 통해 객체는 필요한 의존성만 제공받으므로, 코드의 변경에 더 유연하게 대응할 수 있다.
  * 테스트 시에 실제 객체 대신 `Mock` 객체를 주입할 수 있기 때문에 단위 테스트 시에 용이하다.

## 스프링에서의 IoC와 DI

* 스프링에서는 스프링 컨테이너를 통해 `IoC`와 `DI`가 이루어진다. 떄문에 스프링 컨테이너를 **IoC 컨테이너**, **DI 컨테이너** 라고 부르기도 한다.
* 클래스 사이의 의존 관계를 `Bean` 설정 정보를 바탕으로 컨테이너가 자동으로 연결해주는 방식으로 제공한다.
* 스프링에서는 `@Component`가 포함된 애노테이션, `@Configuration`과 `@Bean`, `XML` 설정 파일을 통해 특정 클래스를 스프링 빈으로 등록할 수 있다.
* 스프링이 이렇게 다양한 형식을 지원할 수 있는 이유는 스프링 컨테이너 밑에 `BeanDefinition` 이라는 추상화가 잘 설계되어 있기 때문이다.
* 스프링에서 `BeanFactory` 또는 `ApplicationContext`라는 객체가 스프링 컨테이너의 역할을 해주며, `ApplicationContext`가 `BeanFactory`의 기능을 상속받고 추가적으로 메시지소스 국제화 기능, 환경 변수 등 부가 기능을 제공한다.

**의존관계 주입 방법**

* **필드 주입**
  * **장점** : 사용하기 편하다.
  * **단점** : 테스트하기 어렵고, DI 컨테이너와 결합도가 커진다.
* **수정자 주입**
  * **장점** : 선택적으로 의존관계를 주입할 수 있다.
  * **단점** : `setter`를 `public`으로 열어두어야 하기 때문에 불변이 보장되지 않는다.
* **★생성자 주입★**
  * **장점** : 불변성이 보장되고, `NPE`를 방지할 수 있다.
  * **단점** : 필요한 인자가 많아질수록 코드도 길어진다.(`@RequiredArgsContructor`로 보완 가능)

**가장 권장되는 주입 방법은 생성자 주입이다.** 왜냐하면, **생성자 주입**은 객체를 생성할 때 딱 한 번만 호출되어 **불변한 설계**가 가능하고, 의존관계 주입이 누락이 됐을 때 유일하게 컴파일 에러로 잡아준다. 또한 유일하게 **순환 참조**가 발생했을 때 컴파일 에러로 잡아준다.

\\

### 참고

* [참고 블로그](https://steady-coding.tistory.com/600)
* [참고 사이트](https://f-lab.kr/insight/understanding-spring-ioc-di?gad_source=1\&gclid=CjwKCAjwt-OwBhBnEiwAgwzrUqM20CkKpKwzRtOZBIySqYwtBWM7_Y0V_qyOcfhQ4mUt_o9tm7e4zRoCBT0QAvD_BwE)
