본문 바로가기

Backend/SpringBoot

IoC, DI 개념과 간단한 예제

최근에 다시 공부하며 정리한 내용을 업로드했습니다!
이 글보다는 > https://shinsunyoung.tistory.com/133 < 포스팅을 읽는 것을 추천드립니다.

IoC/DI

스프링 공부를 하면 가장 기본적인 내용이자 가장 어려운 내용이지만 중요한 내용인 IoC와 DI에 대해 정리해보았다.

컨테이너란?

IoC와 DI를 이해하기 전에 먼저 이해해야 할 개념이 있다. 그것은 바로 '컨테이너'이다.

컨테이너란, 우리 대신 객체의 생성과 소멸 같은 부분을 전담해주는 역할을 한다.

비유를 하자면 주식을 주식 전문가에게 맡기는 것과 같다고 생각하면 된다.

IoC란(Inversion of Control)?

그대로 해석을 돌리면 제어의 역전이라고 한다.

제어는 무언가를 조종하고 다루는 것, 역전은 바뀌는 것이다.

즉, 무언가를 조종하고 다루는 존재가 바뀌는 것을 IoC라고 한다.

우리는 프로그램을 다룰 때, 우리가 직접 조종을 하곤 한다. (예를 들어 객체의 생성을 직접 한다거나)

그러나 스프링에서는 우리가 아닌 다른 존재(컨테이너)가 조종을 한다.

결과적으로, 스프링의 객체들을 생성하고, 제어하고, 소멸하는 존재는 컨테이너이다.

그래서 이것을 제어의 역전이라고 하는 것이다.

DI란?

그렇다면 DI는 무엇일까? DI를 한국어로 풀어쓰면 의존성 주입이다.

DI는 소스 코드 내에서 모든 것이 이루어지는 것이 아닌, 구현체를 외부에서 주입을 받는 것이다.

사실 이렇게 설명하면 제대로 이해가 안 갈 수도 있으니 간단한 예제를 준비했다.

사용하는 디렉토리 구조

의존성 주입을 위해 필요한 application.xml은 src/main/resources에 넣어야 한다.

원래 사용하는 방법 - 객체를 통한 주입

Pakage : di_example1

MessageBean.java

package di_example1;

public interface MessageBean {
	public void meow(String name);

}

MessageBeanKr.java

package di_example1;

public class MessageBeanKr implements MessageBean {

	@Override
	public void meow(String name) {
		System.out.println(name + "는 야옹야옹");
	}
}

CatAndDog.java

package di_example1;

public class CatAndDog {

	public static void main(String[] args) {
		MessageBean bean = new MessageBeanKr();
		bean.meow("고양이");
		
	}
}

실행화면

우리가 평소에 사용하는 방법이자 가장 잘 알고 있는 방법으로

  1. MessageBean 객체를 생성해서 고양이라는 문자열을 넘겨준다.
  2. sayHello에서 MessageBeanKr의 sayHello를 호출한다.
  3. 받아온 이름(고양이)으로 출력을 해준다.

여기까지는 특별할게 없다.

DI를 사용하는 방법 - 의존성 주입

Package : di_example2

MessageBean.java

package di_example2;

public interface MessageBean {
	public void walwal();

}

MessageBeanEn.java

package di_example2;

public class MessageBeanEn implements MessageBean {

	private String name;
	private String bow;
	
	// 실제 출력이 되는 부분
	@Override
	public void walwal() {
		System.out.println( name + "는" + bow + "~!");
	}

	// 생성자를 통해 전달(주입)을 하기 위해 생성자를 만들어준다.
	public MessageBeanEn(String name,  String bow) {
		super();
		this.name = name;
		this.bow = bow;
	}
	

}

CatAndDog2.java

package di_example2;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class CatAndDog2 {
	public static void main(String[] args) {
		//application.xml파일에 있는 빈을 가져오기 위해 사용한다.
		ApplicationContext ctx = new GenericXmlApplicationContext("application.xml");
		MessageBean bean = ctx.getBean("messageBean", MessageBean.class);
		bean.walwal();
	}
}

application.xml

<?xml version="1.0" encoding="UTF-8"?>
<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.xsd">

<bean id="messageBean" class="di_example2.MessageBeanEn">
<constructor-arg value="강아지 " /> <!-- 이렇게 해도 되고 -->
<constructor-arg> <value> 멍멍</value> </constructor-arg> <!-- 이렇게 해도 된다 -->

<!--클래스명 객체명 = new 클래스명 (name, bow)와 같다고 볼 수 있다.-->

</bean>
</beans>

이것이 바로 의존성 주입을 하는 예제로,

빈에서 만들어준 것을 주입해주는 형식이다.

즉, 이런 식으로 구현체(name, bow)를 외부에서 주입받는다고 해서 의존성 주입이라고 한다.

빨간 글씨는 빈을 가져오는 과정을 콘솔에서 보여주는 것이다.

DI를 사용하는 이유

  • 유지 보수 비용이 적게 든다.
  • 가져다는 쓰는 형식이기 때문에 코드의 중복을 줄일 수 있다.

참고 문헌

IoC / DI

IOC와 DI 에 대하여 (스프링 개념 이해하기 쉽게 설명)

Spring IOC/DI 개념