의존성주입(Dependency Injection)이란?


의존성 주입 (DI : Dependency Injection)

의존성 관리

Spring framework의 가장 중요한 특징은 객체의 생성과 의존관계를 컨테이너가 자동으로 관리한다는 점이다.
Spring은 IoC를 다음 두가지 형태로 지원한다. (1) Dependency Lookup : 컨테이너가 어플리케이션 운용에 필요한 객체를 생성하고 클라이언트는 컨테이너가 생성한 객체를 검색(Lookup)하여 사용하는 방식. (잘 사용하지않음) (2) Dependency Injection : 대부분 사용하는 방식. 객체 사이의 의존관계를 Spring 설정파일에 등록된 정보를 바탕으로 컨테이너가 자동으로 처리. 따라서 의존성 설정을 바꾸고자한다면 코드수정 없이 설정파일 수정만으로 변경사항을 적용할 수 있어서 유지보수가 향상된다.

의존성 관계

의존성관계란 객체와 객체의 결합이다. 즉, 하나의 객체에서 다른 객체의 변수나 메소드를 이용해야한다면 이용하려는 객체에 대한 객체 생성과 생성된 객체의 레퍼런스 정보가 필요하다.
예를들어 SamsungTV class가 SonySpaker class의 Volumeup 메소드를 사용하고자 한다면 아래와 같이 SamsungTV class 안에 SonySpeaker class에 대한 객체 생성 코드가 반드시 필요하다.

package polymorphism;

public class SonySpeaker {
	public SonySpeaker() {
		System.out.println("======> SonySpeaker Object init");
	}
	
	public void volumeUp() {
		System.out.println("Sony Speaker -- volume up");
	}
	
	public void volumeDown() {
		System.out.println("Sony Speaker -- volume down");
	}

}
package polymorphism;

public class SamsungTV implements TV{
	
	private SonySpeaker speaker;
	
	public void SamsungTV() {
		System.out.println("======> SamsungTV Object init");
	}
	
	public void initMethod() {
		System.out.println("SamsungTV initMethod");
	}
	
	public void destroyMethod() {
		System.out.println("SamsungTV destroyMethod");
	}
	
	public void powerOn() {
		System.out.println("SamsungTV -- power on");
	}
	
	public void powerOff() {
		System.out.println("SamsungTV -- power off");
	}
	
	public void volumeUp() {
		speaker = new SonySpeaker();
		speaker.volumeUp();
	}
	
	public void volumeDown() {
		speaker = new SonySpeaker();
		speaker.volumeDown();
	}

}

결과 >

INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [applicationContext.xml]
INFO : org.springframework.context.support.GenericXmlApplicationContext - Refreshing org.springframework.context.support.GenericXmlApplicationContext@7dc5e7b4: startup date [Wed Aug 07 15:18:15 KST 2019]; root of context hierarchy
INFO : org.springframework.beans.factory.support.DefaultListableBeanFactory - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@3c756e4d: defining beans [tv]; root of factory hierarchy
SamsungTV initMethod
SamsungTV -- power on
======> SonySpeaker Object init
Sony Speaker -- volume up
======> SonySpeaker Object init
Sony Speaker -- volume down
SamsungTV -- power off
INFO : org.springframework.context.support.GenericXmlApplicationContext - Closing org.springframework.context.support.GenericXmlApplicationContext@7dc5e7b4: startup date [Wed Aug 07 15:18:15 KST 2019]; root of context hierarchy
INFO : org.springframework.beans.factory.support.DefaultListableBeanFactory - Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@3c756e4d: defining beans [tv]; root of factory hierarchy
SamsungTV destroyMethod

이 프로그램은 2가지 문제가있다. (1) SonySpeaker 객체가 쓸데없이 2번 생성된다
(2) SonySpeaker를 AppleSpeaker로 교체하고자할때 두개의 메소드를 수정해야만한다.

이러한 문제가 생기는 이유는 Speaker 객체 생성에 대한 코드를 SamsungTV에 직접 명시했기 때문이다.
Spring은 이러한 문제를 의존성주입(DI)을 이용하여 해결한다.

생성자 인젝션(Constructor Injection) 이용하기

컨테이너가 기본생성자 말고 매배견수를 가지는 다른 생성자를 호출하도록 설정할 수 있다. 이를 이용하여 생성자인젝션(Constructor Injection)을 이용한다.

SamsungTV class에 생성자를 추가한다.

package polymorphism;

public class SamsungTV implements TV {

	private SonySpeaker speaker;

	public void SamsungTV() {
		System.out.println("======> SamsungTV Object init");
	}

	public void SamsungTV(SonySpeaker speaker) {
		System.out.println("======> SamsungTV Object init 2");
		this.speaker = speaker;
	}

	public void initMethod() {
		System.out.println("SamsungTV initMethod");
	}

	public void destroyMethod() {
		System.out.println("SamsungTV destroyMethod");
	}

	public void powerOn() {
		System.out.println("SamsungTV -- power on");
	}

	public void powerOff() {
		System.out.println("SamsungTV -- power off");
	}

	public void volumeUp() {
		speaker.volumeUp();
	}

	public void volumeDown() {
		speaker.volumeDown();
	}
}

스프링 설정파일 (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"
	xmlns:util="http://www.springframework.org/schema/util"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
	
	<bean id="tv" class="polymorphism.SamsungTV">
		<constructor-arg ref="sony"></constructor-arg>
	</bean>

	<bean id="sony" class="polymorphism.SonySpeaker" />
</beans>

결과 >

INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [applicationContext.xml]
INFO : org.springframework.context.support.GenericXmlApplicationContext - Refreshing org.springframework.context.support.GenericXmlApplicationContext@7dc5e7b4: startup date [Wed Aug 07 15:56:41 KST 2019]; root of context hierarchy
INFO : org.springframework.beans.factory.support.DefaultListableBeanFactory - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@6d8a00e3: defining beans [tv,sony]; root of factory hierarchy
======> SonySpeaker Object init
======> SamsungTV Object init 2
SamsungTV -- power on
Sony Speaker -- volume up
Sony Speaker -- volume down
SamsungTV -- power off
INFO : org.springframework.context.support.GenericXmlApplicationContext - Closing org.springframework.context.support.GenericXmlApplicationContext@7dc5e7b4: startup date [Wed Aug 07 15:56:41 KST 2019]; root of context hierarchy
INFO : org.springframework.beans.factory.support.DefaultListableBeanFactory - Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@6d8a00e3: defining beans [tv,sony]; root of factory hierarchy

Spring 컨테이너가 알아서 sonyspeaker를 먼저 생성하고 이를 samsungtv의 2번째 생성자에 주입하여 samsungTV가 sonyspeaker의 메소드를 문제없이 사용하게 되었다.

setter 인젝션 이용하기

SamsungTV class에 setter 메소드를 추가한다.

package polymorphism;

public class SamsungTV implements TV {

	private Speaker speaker;

	public Speaker getSpeaker() {
		System.out.println("=====> getSpeaker() call");
		return speaker;
	}
	public void setSpeaker(Speaker speaker) {
		System.out.println("=====> setSpeaker() call");
		this.speaker = speaker;
	}
	public SamsungTV() {
		System.out.println("======> SamsungTV Object init");
	}
	public void initMethod() {
		System.out.println("SamsungTV initMethod");
	}

	public void destroyMethod() {
		System.out.println("SamsungTV destroyMethod");
	}

	public void powerOn() {
		System.out.println("SamsungTV -- power on");
	}

	public void powerOff() {
		System.out.println("SamsungTV -- power off");
	}

	public void volumeUp() {
		speaker.volumeUp();
	}

	public void volumeDown() {
		speaker.volumeDown();
	}

}

스프링 설정파일(xml)에 <constructor-arg> 대신에 <property> element를 사용한다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:util="http://www.springframework.org/schema/util"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

	<bean id="tv" class="polymorphism.SamsungTV">
		<property name="speaker" ref="apple" />
	</bean>

	<bean id="sony" class="polymorphism.SonySpeaker" />
	<bean id="apple" class="polymorphism.AppleSpeaker" />
</beans>

결과

INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [applicationContext.xml]
INFO : org.springframework.context.support.GenericXmlApplicationContext - Refreshing org.springframework.context.support.GenericXmlApplicationContext@7dc5e7b4: startup date [Wed Aug 07 16:44:37 KST 2019]; root of context hierarchy
INFO : org.springframework.beans.factory.support.DefaultListableBeanFactory - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@573f2bb1: defining beans [tv,sony,apple]; root of factory hierarchy
======> SamsungTV Object init
======> AppleSpeaker Object init
=====> setSpeaker() call
======> SonySpeaker Object init
SamsungTV -- power on
Apple Speaker -- volume up
Apple Speaker -- volume Down
SamsungTV -- power off
INFO : org.springframework.context.support.GenericXmlApplicationContext - Closing org.springframework.context.support.GenericXmlApplicationContext@7dc5e7b4: startup date [Wed Aug 07 16:44:37 KST 2019]; root of context hierarchy
INFO : org.springframework.beans.factory.support.DefaultListableBeanFactory - Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@573f2bb1: defining beans [tv,sony,apple]; root of factory hierarchy

p namespace 사용하기

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:util="http://www.springframework.org/schema/util"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

	<bean id="tv" class="polymorphism.SamsungTV" p:speaker-ref="apple">
	</bean>

	<bean id="sony" class="polymorphism.SonySpeaker" />
	<bean id="apple" class="polymorphism.AppleSpeaker" />
</beans>

이와같이 p namespace를 통해 객체를 주입할 수 있다.




© 2020. by berrrrr

Powered by berrrrr