안녕하세요. 성조입니다.
이번 포스팅에서는 DI(Dependency Injection)와 묶음으로 자주 설명되는 IoC 컨테이너(Inversion of Control)에 대해서 정리해 보려 합니다.
혹여나 올바르지 못한 지식이 전달되고 있다면 언제든지 댓글 남겨주시면 감사드리겠습니다!
DI의 개념이 필요한 곳입니다. DI를 검색해서 학습하시거나 아래의 포스팅을 읽고 이해한 후 진행해 주시면 감사드리겠습니다.
2023.04.04 - [Java ☕/Spring] - [Spring] DI(Dependency Injection)이란?
IoC (Inversion Of Control)란?
IoC는 제어 역전, 제어 반전, 역제어 등의 뜻을 가지고 있다. 이번 포스팅에서는 '제어의 역전'이라고 얘기한다.
제어의 역전은 애플리케이션의 흐름을 개발자가 아닌 프레임워크가 제어를 담당하는 디자인 패턴이다.
전통적으로 프로그래밍에서 개발자가 직접적으로 라이브러리를 호출하여 흐름을 제어하거나, 객체의 생명주기를 관리해 왔다.
IoC에서는 저수준의 구성요소에 대한 통제를 상위 모듈에 위임하여 프레임워크에서 외부 라이브러리의 코드를 호출하거나, 객체의 생명주기를 제어하고, 언제 어떤 객체를 사용할 것인지의 의존성 관리를 프레임워크(Spring)에게 결정할 수 있게 맡기는 것이다.
IoC를 적용하지 않은 코드
public class TextEditor {
private SpellChecker checker;
public TextEditor() {
this.checker = new SpellChecker();
}
}
'TextEditor'는 'SpellChecker'에 의존하는 코드이다.
'TextEditor'는 'SpellChecker'를 직접 생성하고 관리도 해야 하므로 'SpellChecker'의 구현체가 변경되면 'TextEditor'도 변경해야 한다.
IoC를 적용한 코드
public class TextEditor {
private SpellChecker checker;
public TextEditor(SpellChecker checker) {
this.checker = checker;
}
}
'TextEditor'는 'SpellChecker'를 직접 생성하거나 관리하지 않는다. 대신, 'TextEditor'의 생성자를 통해 'SpellChecker' 인스턴스가 주입되어 사용되는 코드이다. 이렇게 적용한 코드가 의존성 주입(DI)이며, IoC의 한 형태이다.
IoC 컨테이너
'IoC 컨테이너'의 개념을 구현한 도구나 기능 정도로 얘기한다.
스프링에서는 IoC 컨테이너는 스프링 프레임워크가 제공하는 핵심 기능 중 하나로, Bean 객체의 생성, 연결, 소멸 등 생명주기를 관리하며, Bean 사이의 의존성을 주입하는 역할을 수행한다.
'IoC'는 무엇(What)을 설명하는 원칙으로 사용된다. (객체를 ~ )
'IoC 컨테이너'는 어떻게(HoW)를 설명하는 구현체 또는 도구 정도이다. (XX로 옮긴다.)
IoC 컨테이너 동작 과정
스프링의 IoC 컨테이너는 IoC 원칙을 구현해 준다.
IoC 컨테이너는 다음과 같은 순서로 동작한다.
1. Bean 설정 파일 읽기
스프링 IoC 컨테이너는 먼저 Bean 설정 파일을 읽어 들인다.
xml 파일에는 애플리케이션에서 사용할 객체(Bean)의 정보와 이들 객체 간의 의존성 정보가 정의되어 있다.
[xml]
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="exampleBean" class="com.example.ExampleBean">
<property name="message" value="Hello Spring!" />
</bean>
</beans>
설정에서 'exampleBean'라는 ID를 가진 bean이 정의된다.
'com.example.ExampleBean'이라는 클래스의 인스턴스를 활용해서 'message'라는 프로퍼티 값에 'Hello Spring!'을 설정했다.
2. Bean 생성과 의존성 주입
위 설정 파일을 읽은 후. 스프링 IoC 컨테이너는 설정에 따라 필요한 Bean을 생성하고, 이들 Bean 간의 의존성을 주입한다.
이 과정을 'Bean 팩토리 후처리(Bean Factory Post Processing)'라고 한다.
BeanPostProcessor 인터페이스를 구현한 클래스들이 작동하며, Bean의 생성과 초기화 과정에서 발생하는 추가적인 처리를 수행한다.
3. Bean 사용
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
ExampleBean exampleBean = (ExampleBean) context.getBean("exampleBean");
exampleBean.doSomething();
'beans.xml'설정 파일을 읽어 들이는 ApplicationContext를 생성하고, 'exampleBean'이라는 ID를 가진 Bean을 얻어와 메서드를 호출하게 된다.
IoC와 DI의 관계
IoC는 위에 설명된 것처럼 제어권을 역전시켜서 프레임워크에게 프로그램의 제어를 맡기는 개념이다.
의존성 주입 DI(Dependency Injection)는 IoC의 구성 방식 중 하나로 클래스의 의존성을 직접 코드 내에서 해결하는 대신 외부에서 주입하는 방식을 말한다.
스프링에서는 DI를 XML 설정, 어노테이션 등을 통해서 구현할 수 있다.
IoC의 장점과 단점
많은 장단점이 존재하겠지만 간략한 설명을 진행한다.
[장점]
재사용성(모듈화) 증가, 테스트 용이성 향상, 유연성 및 확장성 증가, 결합도를 낮추는 등 다양한 장점들이 존재한다.
- 유연성: IoC를 통해 프레임워크에게 하위 수준의 모듈을 모두 위임했기 때문에 상위 수준의 모듈인 비즈니스 로직에 집중할 수 있게 되는 장점이 있다.
- 재사용성 증가 : 의존성 주입(DI)을 통한 IoC를 사용하면, 특정 구성요소를 컨트롤러마다 서비스 객체를 직접 생성할 필요 없이, 프레임워크가 해당 서비스 객체를 컨트롤러에 주입해 줄 수 있기 때문에 여러 곳에서 재사용할 수 있게 된다.
[단점]
- IoC를 사용하면 간혹 실행 지점에서 오버헤드 에러가 발생되는 경우도 있다.
- 높은 자유도가 있는 만큼 복잡성이 매우 커질 수 있다.
- 프레임워크에 제어를 맡기는 것이므로 너무 의존적일 수 있다.
- 프레임워크가 전반적인 흐름을 관리할 수 있도록 하기 때문에 러닝 커브가 존재한다.
오타나 궁금한 부분이 있다면 언제든지 댓글 달아주시면 감사드리겠습니다!
다음 포스팅 때 뵙겠습니다!
- 참조 -
https://docs.spring.io/spring-framework/reference/core/beans/basics.html
'Java ☕ > Spring' 카테고리의 다른 글
[Spring] DI(Dependency Injection)이란? (0) | 2023.04.04 |
---|