개요
개발 면접 질문에서 항상 많이 받았던 질문인 DI, IoC 에 대한 정리가 필요하다고 생각해 글을 작성합니다.
책을 읽다보니, DI 보단 IoC 가 더 근간에 가까운 개념이었다는 것을 알게 되었습니다. 둘을 분리해서 IoC는 이런 것이고 DI는 이런 것이다! 라고 설명하기 어렵지만, 최대한 두괄식으로 설명해보겠습니다. 그리고 DI 및 IoC 에 대한 이해는 확실히 예제가 있어야 이해가 잘 되는 것 같습니다.
먼저 설명할 것은..
IoC 란?
흔히 라이브러리와 프레임워크를 두고 이 개념을 설명합니다. 저는 그런 설명을 하고 나서 면접에 떨어졌습니다 ㅎㅎ..
뭐랄까 기술 면접은 형식적인 답변을 기대해서 한다기 보다 그 사람이 해당 기술에 대해서 진지하게 알아보고 있는 지 정성적인 부분을 보는 것이라 느껴졌습니다.
우리 말로는 제어의 역전이며, 프로그램의 제어 흐름 구조가 뒤바뀌는 것이라고 정의할 수 있습니다.
이제 IoC 에 대한 부가설명을 하겠습니다.
만약 제가 자바 프로그램을 작성 중이고 의존관계가 아래와 같다면,
A 는 B를 의존하고, B는 C를 의존하게 되겠죠? 이를 자바 프로그램 관점에서 보면, 모든 오브젝트는 자기가 사용할 클래스를 능동적으로 결정하고 언제쓸지 어떻게 쓸지 스스로 관장합니다. 작업을 사용하는 쪽 (위 예에선 A) 에서 제어하는 구조이죠.
제어의 역전은 이런 제어 흐름의 개념이 거꾸로 뒤집히는 것입니다. 그럼 C -> B -> A 이런식으로 되는..? (X)
오브젝트는 자신이 사용할 오브젝트를 스스로 생성하거나 선택하지 않습니다. 대신 모든 제어 권한을 자신이 아닌 다른 대상에게 위임을 합니다.
일단 일반적인 IoC 개념을 이 정도로 알아보고, Spring의 IoC 개념또한 따로 있으니 이것도 알아보는 것이 좋겠습니다.
Spring IoC
스프링에선 빈(bean) 의 생성과 관계설정 같은 제어를 담당하는 IoC 오브젝트를 빈 팩토리(bean factory) 및 좀 더 넓은 표현인 애플리케이션 컨텍스트(application context) 라고 부릅니다.
애플리케이션 컨텍스트는 별도의 정보를 참고해서 빈(오브젝트) 생성, 관계설정 등의 제어 작업을 총괄합니다.
...
DI 란?
Dependency Injection, 우리 말로는 '의존성 주입'
단어 자체로는 와닿지 않네요.. 사전적인 정의는 다음과 같습니다.
오브젝트 레퍼런스를 외부로부터 제공(주입)받고 이를 통해 여타 오브젝트와 다이내믹하게 의존관계가 만들어지는 것
허허..사전적인 정의는 더더욱이 와닿지 않네요.
앞서 봤던 그림처럼 의존관계가 위와 같이 있다면 의존관계는 방향이 있습니다. B에 의존을 하는 A는 B의 변화에 영향을 받습니다. 반대로 B는 A의 변화에 영향을 받지 않죠.
이러한 설명은 설계관점에서 설명을 한 것이고, 런타임 시에 오브젝트 사이에 만들어지는 의존관계에 대해서도 알아봅시다. 런타임 시 만들어지는 DI는 설계관점에서의 DI가 실체화 된 것입니다.
런타임 시 만들어지는 DI는 구체적인 의존 오브젝트와 그것을 사용할 주체, 보통 클라이언트라고 부르는 오브젝트를 런타임 시에 연결해주는 작업을 말합니다.
정리하면 의존관계 주입은 아래 3가지 조건을 충족하는 작업을 말합니다.
- 클래스 모델이나 코드에는 런타임 시점의 의존관계가 드러나지 않는다. 그러기 위해서는 인터페이스에만 의존하고 있어야 한다.
- 런타임 시점의 의존관계는 컨테이너나 팩토리 같은 제3의 존재가 결정한다.
- 의존관계는 사용할 오브젝트에 대한 레퍼런스를 외부에서 제공(주입)해줌으로써 만들어진다.
DI의 핵심은 설계 시점에선 알지 못했던 두 오브젝트의 관계를 맺도록 도와주는 제3의 존재(애플리케이션 컨텍스트, 빈 팩토리, IoC 컨테이너)가 있다는 것입니다.
여기 DaoFactory 클래스, UserDao 클래스가 있고 ConncectionMaker 인터페이스 및 이에 대한 구현클래스인 DConnectionMaker 가 있습니다.
public class DaoFactory {
public UserDao userDao() {
return new UserDao([...option]);
}
}
public class UserDao() {
// DI 적용 전 코드
private ConnectionMaker connectionMaker;
public UserDao() {
connectionMaker = new DConnectionMaker();
}
}
UserDao 클래스에 대해 DI를 적용하기 전 후 코드는 위, 아래와 같은데요.
public class UserDao() {
// DI 적용 후 코드
private ConnectionMaker conenctionMaker;
public UserDao(ConnectionMaker connectionMaker) {
this.connectionMaker = connectionMaker;
}
...
}
DaoFactory 는 의존관계를 결정해주는 제 3의 존재 이자 DI 컨테이너 입니다.
DI 컨테이너는 자신이 결정한 의존관계를 맺어줄 클래스의 오브젝트를 만들고 이 생성자의 파라미터로 오브젝트의 레퍼런스를 전달해줍니다.
DaoFactory 코드를 보면 위 문구가 바로 적용이 되는 것을 볼 수 있죠? ConnectionMaker 와 UserDao 간에 의존관계가 만들어졌습니다. UserDao 오브젝트는 생성자를 통해 주입받은 DConnectionMaker 오브젝트를 언제든지 사용할 수 있어요.
이렇듯 DI 컨테이너를 통해 런타임 시 의존 오브젝트(ex. DConnectionMaker)를 사용할 수 있도록 그 레퍼런스를 전달받는 과정이 마치 메소드(생성자)를 통해 DI 컨테이너가 UserDao에게 주입해주는 것과 같다고 해서 이를 의존관계 주입이라고 부릅니다.
의존관계 주입(DI)이란 DI 컨테이너를 통해 의존 오브젝트의 레퍼런스를 전달받는 과정을 말한다.
DI는 자신이 사용할 오브젝트에 선택과 생성 제어권을 외부로 넘기고 자신은 수동적으로 주입받은 오브젝트를 사용한다는 점에서 IoC의 개념에 잘 들어맞습니다. 스프링 컨테이너의 IoC는 주로 의존관계 주입 또는 DI라는 데 초점이 맞춰져 있고 그래서 스프링을 IoC 컨테이너 외에도 DI 컨테이너, DI 프레임워크라고도 부르는 것입니다.
소감
와우..정말 제가 단순 면접을 위해서 DI를 후려치기 식으로 공부했다는 것을 실감하게 해주는 과정이었습니다. 스프링을 사용해 개발하는 사람이라면 위 개념에 대해선 꼭 제 블로그의 글이 아니더라도 상세하게 알아보면 개발할 때 더 도움이 될 거 같습니다 ㅎㅎ 긴 글 읽어주셔서 감사합니다!
출처
토비의 스프링 3.1 - v1
'BackEnd > Spring' 카테고리의 다른 글
싱글톤 컨테이너 (0) | 2023.04.29 |
---|---|
스프링 컨테이너와 스프링 빈 (0) | 2023.04.22 |
객체지향 설계와 스프링 (0) | 2023.04.16 |
Spring 배치 관련 정리 (2) | 2022.12.21 |
Intellij_Spring 초기 세팅시 참고한 사이트들 (0) | 2018.07.25 |
댓글