JAVA

[Spring] IoC, DI, 컨테이너

로춘남 2021. 10. 19. 08:52
728x90


IoC (Inversion of Control) - 제어의 역전

- 프로그램의 제어 흐름을 개발자가 결정하는 것이 아니라, 외부에서 결정을 하는 것. 여기서의 흐름은 메소드나 객체의 호출을 의미.

- 객체를 개발자가 Test test = new Test(); 이런식으로 만드는것이 아니라 스프링이 스스로 객체를 생성해서 필요한곳에 사용 할 수 있게 해준다.

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

프로그램의 제어 흐름을 직접적으로 하는 것이 아닌 외부에서 관리하는 것을 우리는 제어의 역전! 이라고 부른다.

 

 

※ 프레임워크 vs 라이브러리

- 프레임워크는 내가 작성한 코드를 제어하고, 대신 실행하는 녀석 ex) JUnit

- 내가 작성한 코드가 직접 제어의 흐름을 담당한다면 그것은 라이브러리

 

 

DI(Dependency Injection) - 의존관계 주입

- 의존하는 객체를 직접적으로 생성하는것이 아니라, 외부에서 생성한 이후 주입하는 것.

- 의존관계는 정적인 클래스 의존관계와, 실행 지점에 결정되는 동적인 개체(인스턴스) 의존 관계 둘을 분리해서 생각해야함.

출처: 인프런 스프링 핵심원리 기본편(김영한)

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

 

출처 : 인프런 스프링 핵심원리 기본편(김영한)

애플리케이션 실행 시점(런타임)에 외부에서 실제 구현 객체를 생성하고 클라이언트에 전달해서 클라이언트와 서버의 실제 의존관계가 연결되는것을 의존관계주입 이라고 한다. 의존관계 주입을 사용하면 클라이언트 코드를 변경하지 않고, 클라이언트가 호출하는 대상의 타입 인스턴스를 변경 할 수 있음. 또한 정적인 클래스 의존관계를 변경하지 않고, 동적인 객체 인스턴스 의존관계를 쉽게 변경 할 수 있음.

 

의존관계를 주입하기 위해선 다음의 조건이 필요하다.

1) 클래스 모델이나 코드에는 런타임(실행) 시점의 의존관계가 드러나지 않는다. 정적인 클래스 의존관계가 아닌 동적인 객체 인스턴스 의존관계이기 때문에 인터페이스에만 의존하고 있어야한다.

2) 런타임 시점의 의존관계는 외부에서 결정한다.

3) 외부에서 실제 구현 객체(사용할 오브젝트에 대한 레퍼런스)를 생성하고 클라이언트(사용할 오브젝트)에 전달(주입) 함으로써 의존관계가 연결되는 것이다.

 

example)

private Car myCar = new BMW();

Car가 인터페이스고 BMW가 구현 객체라면, 런타임 이전에, 즉 코드상으로 BMW 클래스를 의존하는 것을 알 수 있다.

private Car myCar -> 이러면 Car에 어떠한 차가 들어올지 알 수가 없음. 왜냐? 런타임 시점에서 의존관계가 나타나지 않기 때문에.

즉, 이렇게 인터페이스에서만 의존하고 의존환계 주입이 발생 할 수 있다.

 

 

IoC, DI를 사용했을때 이점

Java만으로는 DIP(의존관계 역전 원칙)과 OCP(개방-폐쇄 원칙)을 지켜가며 객체지향적으로 설계하는데 어려움이 있었는데, 이를 해결 할 수 있다.

즉, 스프링을 사용하면 좋은 객체 지향 애플리케이션을 개발하기 편해지며, 스프링은 이를 도와주는 프레임워크이다.

스프링이 좋은 객체지향 애플리케이션을 개발하는데 도움을 주는 프레임워크인것처럼, 스프링부트는 스프링의 기술들을 좀 더 편리하게 사용하는데 도움을 주는 프레임워크이다.

 

 

IoC 컨테이너, DI 컨테이너

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

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

728x90