DI와 IoC에 대해 아는 만큼 설명해주실 수 있을까요?
간단히 요약하면, DI는 객체 간의 의존성을 외부에서 주입하는 것으로 프로그램을 잘 만드는 레시피, 과정 중 하나라고 볼 수 있으며 IoC는 제어의 주도권을 개발자에서 제 3자 또는 프레임워크나 컨테이너로 넘기는 설계 원칙으로 프로그램을 잘 만드는 방법이라고 생각합니다. 스프링은 이 같이 프로그램을 잘만들기 위한 원칙과 레시피를 잘 준수 할 수 있도록 도움을 주는 역할을 한다고 볼 수 있습니다.
DI는 디펜던시 인젝션으로 의존성 주입이라고 합니다. 하나의 객체가 다른 객체에 의존성을 직접적으로 만들지 않고, 외부에서 주입받도록 하는 디자인 패턴입니다. 일반적으로 이는 코드의 유연성과 재사용성을 높이고 테스트하기 쉽게 만들어주기 위해 사용됩니다.
IoC는 인버전 오브 컨트롤의 약자로, "제어의 역전"이라고 합니다. 기존에는 개발자가 프로그램의 흐름과 제어를 직접 다루었지만, IoC에서는 프레임워크나 컨테이너가 제어의 흐름을 가져가게 됩니다. 이를 통해 객체지향 설계 원칙을 따를 수 있도록 하고 IoC를 적용함으로써 코드의 의존성을 외부로 옮기고, 객체의 생성 및 관리를 외부에 위임하여 개발자는 중요한 비지니스로직 개발에 힘쓸 수 있도록 합니다.
추가질문
스프링 프레임 워크에서 DI와 IoC 개념이 사용되는 예시를 설명 할 수 있나요?
Spring 프레임워크는 의존성 주입을 통하여 제어의 역전을 사용하는 대표적인 예시 중 하나입니다. 개발자의 편의를 위해서 스프링 프레임워크는 다양한 어노테이션을 제공합니다. 프레임워크가 지정한 약속에 따라 적합한 어노테이션을 사용하면 간편하게 어플리케이션을 개발 할 수 있도록 많은 도움을 주고 있습니다.
처음 이 개념을 사용하고 경험하게 된 것은 간단한 프로젝트가 Controller, Service, Repository 3 계층 디자인 패턴으로 나뉠때 이 개념을 처음 학습하게 되었습니다. 특히 데이터베이스와 연결되는 JDBC 템플릿 객체가 3계층 모두 필요로 한 시점에서 되었는데 각 계층마다 템플릿을 생성하니 코드 중복이 많았으며 작동은 되지만 실질적으로 동일한 객체가 아닌 문제점이 있었습니다. 이는 각 계층이 직접 객체를 생성하는 강한 결합 상태 였습니다. 또한, 다른 클래스의 호출을 통해 JDBC를 얻어 올 때, 그 제어의 순서가 Controller는 Service의 JDBC를 호출하여 가져오고, Service또한 Repository의 JDBC를 호출 하는 등 Controller부터 Service→ Repository 순서로 제어의 흐름을 가지고 있었습니다.
하지만 DI를 활용하니 반대의 상황이 나타났습니다. Repository 계층에서 JDBC를 최초 생성하고, Service는 Repository를, Controller는 Service를 주입 받으면서 가장 하위 계층의 단 한 번의 객체 생성으로 동일한 JDBC 템플릿을 재사용 할 수 있어 느슨한 결합을 만들 수 있었습니다. JDBC를 생성하는 제어권은 Repository에서부터 시작 되기 때문에 Service → Controller 순서로 객체에 대한 제어권이 역전된 모습을 볼 수 있었습니다. 이를 통해 의도한대로 하나의 객체를 여러곳에서 사용 할 수 있게 되어 전체적인 코드량이 획기적으로 줄어들고 구분하는 것도 편해지는 것을 느꼈습니다. 그리고 실제 DB와 연관있는 Repository 계층만이 JDBC를 제어를 할 수 있도록 올바른 제어권 순서도 가지게 된 것을 확인 할 수 있었습니다.
추가질문
스프링 프레임 워크에서 어떤 과정으로 DI가 진행될까요?
스프링에서는 IoC 컨테이너라는 곳에 Bean이란 객체들이 등록되면서 스프링부트 환경 안에서 어디에서든 주입하고 재활용 할 수 있습니다.
어떠한 클래스에 @Component라는 어노테이션을 작성하면, 스프링 프레임워크 내 환경이 실행 될 때 ComponentScan을 통해 어플리케이션 하위 모든 클래스에서 위 어노테이션을 찾아내고 Bean으로 등록합니다. 그럼 해당 클래스는 어디서든 주입하여 사용 할 수 있게 됩니다. Bean은 기본적으로 싱글톤으로 등록, 사용되기 때문에 유일성을 보장받게됩니다.
앞서 말씀드린 3Layer인 Controller, Service, Repository는 각각 @Controller, @Service, @Repository라는 어노테이션을 작성하면 빈으로 검색될 대상이 됩니다. 그 이유는 각 주석 내부로 들어가보면 @Component라는 어노테이션을 포함하고 있기 때문입니다.
이처럼 IoC컨테이너에 위 컴포넌트들을 빈으로 등록하면 개발자가 의도한대로 빈의 객체를 여러곳에서 사용, 수정 할 수 있게 되며, 코드를 간결하게 해주어 유지보수적으로 유리하고 필요할때마다 새로운 객체를 계속해서 생성할 필요가 없기 때문에 불필요한 메모리 사용도 적어집니다.
추가질문
스프링 프레임 워크에서 그럼 장점뿐만이 아니라 단점도 있을까요?
단점으로는 처음에는 DI와 IoC가 새로운 개념이었기 때문에 조금 생소하게 느껴졌었습니다. 또한 실제로 복잡했던 코드가 간편히 어노테이션 등으로 획기적으로 줄어들면서 한편으로는 어떻게 이렇게 작동하는지 궁금하기도 했지만 그 내부의 작동 원리를 파악하기에 다소 복잡한 구성을 가지고 있어서 잘못 사용한 경우 문제를 발견하고 해결하는데 어려움이 있기도 했습니다. 이를 통해 어노테이션의 정확한 용도와 작동 흐름을 공부하고자 노력하게 되었습니다. 매우 단순한 프로젝트의 경우 이러한 DI 자체가 오히려 코드, 실행의 복잡성을 증가시키거나 코드 양이 오히려 증가 할 가능성도 있을 것 같다고 생각합니다.