본문 바로가기

개발자노트/Spring

의존성 주입 ( DI = Dependency Injection )

의존성 주입(dependency injection)은 하나의 객체가 다른 객체의 의존성을 제공하는 테크닉이다. 

 

즉, 외부에서 두 객체 간의 관계를 지정해주는 디자인 패턴으로, 인터페이스를 사이에 두어 클래스 레벨에서는 

의존관계가 고정되지 않도록 하고, 서버 런타임 시 관계를 동적으로 주입하여 결합도를 떨어트릴 수 있게 해준다.

 

의존성 주입에는 크게 두가지 방법이 있다.

1) 생성자 인젝션

2) 수정자(Setter) 인젝션

 

 

 

 

1) 생성자 인젝션

Iphone의 기본생성자 외에 Watch와 battery를 인자로 필요로 하는 생성자를 만든다.

 

 

그리고 .xml 파일 ( 스프링 컨테이너 ) 에는

Galaxy 객체를 phone에 담고, 이 때 이 멤버변수는

ref = "주입할 객체명"

value= "문자열 혹은 기본형 데이터"

를 주입할 수 있다.

 

생성자 주입은 먼저 생성자의 인자에 사용될 빈을 찾거나 빈 팩토리에서 만든다. ( bean id="gw" )
그 후에 찾은 인자 빈으로 주입하려는 빈의 생성자를 호출하여 사용한다.
즉, 먼저 빈을 생성하는 것이 아니라 주입하려는 빈을 먼저 찾는다.

 

 

 

2) 수정자 인젝션 (setter)

 

위와 같이 들어가는 멤버변수가 정해져있는 상태라면

생성자 인젝션이 OOP중 OCP(Open-Closed Principal, 개방-폐쇄 원칙)에 위반되지 않고,

불변성을 보장하기 때문에 더 유용하겠지만,

인자들의 값이 변경될 수 있기 때문에 수정자 인젝션을 사용하는 법도 알아야 한다 생각한다.

 

 

위에 예를 이어서 설명하자면 , 폰은 갤럭시 폰인데 다른 워치를 사용할 수도 있을 것이다.

이 때, Watch의 종류 혹은 배터리의 상태는 변한 객체를 만들어야하기 때문에 setter 인젝션을 사용하는 것이다.

다음과 같이 private 된 멤버변수들을 getter와 setter를 만들어

 

 

watch를 aw ( appleWatch 로 만든 bean) battery를 70으로 넣어준다.

 

 

p네임스페이스 사용법

 

1. xml 파일을 연다

2. 하단에 Namespaces 탭을 누른다

 

3. p 태그 체크해서 활성화

 

 

4. 하단과 같이  xml 상단에 추가된 것을 볼 수 있다.

 

p:멤버변수명-ref = "주입할 객체명"
p:멤버변수명 = "주입할 값"

으로 사용하면 된다.

 

 

 

 

 

뿐만 아니라, 객체의 멤버변수로 컬렉션 또한 사용 가능한데

 

 

List 컬렉션으로 선언 된 datas와

Map 컬렉션으로 선언 된 datas1을 멤버변수로 만들고

 

 

 list를 사용하여 data에 set 해줄 수 있고,

 

 

컬렉션 Set 또한 다음과 같이 사용 가능하며

 

 

 

컬렉션 Map도 다음과 같이 사용 가능하다.

 

 

출력을 위해 main이 존재하는 클래스를 만들면

다음과 같이 작성할 수 있으며, factory.close는 모든 수행이 다 되었을 때만 써주면 된다.

( 한번에 출력을 보고 싶으면 중간에 factory.close() 2개는 지우고 최하단 factory.close만 남기면 됨 )

 

 

출력결과

 

 

 

 

 

 

 

전체코드

 

Client.java

package test;

import java.util.Map;

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

public class Client {
	public static void main(String[] args) {
		// Spring 컨테이너를 동작시킬수있도록 코드작성
		AbstractApplicationContext factory=new GenericXmlApplicationContext("applicationContext.xml");
		TestBean tb=(TestBean)factory.getBean("tb");
		for(String v:tb.getDatas()) {
			System.out.println(v);
			}
		 //factory.close();
		
		TestBean tb2=(TestBean)factory.getBean("tb2");
		for(String v:tb2.getDatas()) {
			System.out.println(v);
		 }
		// factory.close();
		
		TestBean tb3=(TestBean)factory.getBean("tb3");
		Map<String,String> datas=tb3.getDatas1();
		System.out.println(datas);
		factory.close();
		
		// Spring 컨테이너야, 나 폰 객체를 가지고싶어!
		// == Lookup
		//Phone phone=(Phone)factory.getBean("gp");
		//phone.powerOn();
		//phone.powerOff();
		//factory.close();
		
		/*
		BeanFactory bf=new BeanFactory();
		Phone phone=(Phone)bf.getBean(args[0]);
		phone.powerOn();
		phone.volumeUp();
		phone.volumeDown();
		phone.powerOff();
		*/
	}
}

 

 

applicationContext.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:p="http://www.springframework.org/schema/p"
	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/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">

	
	
	
 	<bean id="phone" class="test.Galaxy" init-method="initMethod" destroy-method="destroyMethod" lazy-init="true" >
		<property name="watch" ref="aw"/>  <!--  객체는 ref  -->
		 <property name="battery" value="70" />  <!--  값은 value -->
	</bean>  

	
	<bean id="gp" class="test.Galaxy" p:watch-ref="gw" p:battery="70" />  <!--  p 네임스페이스로도 세터가능  -->
	<bean id="iphone" class="test.IPhone" lazy-init="true" />
	

	<bean id="aw" class="test.AppleWatch" /> 
	<bean id="gw" class="test.GalaxyWatch" />

	<bean id="tb" class="test.TestBean">
		<property name="datas">
			<list>
				<value>서울시</value>
				<value>서울시 관악구</value>
				<value>사당역</value>
			</list>
		</property>
	</bean>
	
	
	<bean id="tb2" class="test.TestBean">
		<property name="datas">
			<set>
				<value>바나나</value> 
				<value>바나나</value>  <!-- set은 중복이 제거된 집합이다. -->
				<value>키위</value>
			</set>
		</property>
	</bean>
	
	
	<bean id="tb3" class="test.TestBean">
		<property name="datas1">
			<map>
				<entry>
					<key><value>아리</value></key>
					<value>미드</value>
				</entry>
				<entry>
					<key><value>아무무</value></key>
					<value>서포터</value>
				</entry>
				<entry>
					<key><value>티모</value></key>
					<value>탑</value>
				</entry>
			</map>
		</property>
	
	</bean>

</beans>

 

 

여러 폰 중 하나 IPhone ( 인터페이스 Phone을 implements )

package test;

public class IPhone implements Phone{
	private Watch watch;
	private int battery;
	
	public IPhone() {
		System.out.println("아이폰 객체생성완료");
	}
	public IPhone(Watch watch, int battery) {
		this.watch=watch;
		this.battery=battery;
	}
	@Override
	public void powerOn() {
		System.out.println("아이폰 전원 ON");
	}
	@Override
	public void powerOff() {
		System.out.println("아이폰 전원 OFF");
	}
	public Watch getWatch() {
		return watch;
	}
	public void setWatch(Watch watch) {
		this.watch = watch;
	}
	public int getBattery() {
		return battery;
	}
	public void setBattery(int battery) {
		this.battery = battery;
	}
	
	
}

 

 

Watch를 implement 하는 GalaxyWatch

package test;


public class GalaxyWatch implements Watch{
	@Override
	public void volumeUp() {
		System.out.println("갤워치 소리 ++");
	}
	@Override
	public void volumeDown() {
		System.out.println("갤워치 소리 ++");
	}
}