본문 바로가기

Spring

[Spring] 의존성 주입(DI), p 네임 스페이스, 컬렉션 사용

728x90
반응형

DI (Dependency Injection ) - 의존관계 주입

DI란 외부에서 두 객체 간의 관계를 결정해주는 디자인 패턴으로,
인터페이스를 사이에 둬서 클래스 레벨에서는 의존관계가 고정되지 않도록 하고
런타임 시에 관계를 동적으로 주입하여 유연성을 확보하고 결합도를 낮출 수 있게 해줌 


의존성을 주입하는 방법

 

1) 생성자 주입 (Constructor Injection)

 

2가지 워치를 번갈아 사용이 가능하도록! 워치 인터페이스를 작성 

package test;

public interface Watch {
	public void volumeUp();
	public void volumeDown();
}

 

AppleWatch, GalaxyWatch 둘다 인터페이스에 연결 

package test;

public class AppleWatch implements Watch{
	public AppleWatch() {
		System.out.println("애플워치 객체생성완료");
	}
	public void volumeUp() {
		System.out.println("애플워치 ++");
	}
	public void volumeDown() {
		System.out.println("애플워치 --");
	}
}
package test;

public class GalaxyWatch implements Watch{
	
	public GalaxyWatch(){
		System.out.println("갤럭시워치 객체생성완료");
	}
	@Override
	public void volumeUp() {
		System.out.println("갤럭시워치 ++");
		// TODO Auto-generated method stub
		
	}
	@Override
	public void volumeDown() {
		System.out.println("갤럭시워치 --");
		// TODO Auto-generated method stub
		
	}
}

 

하기와 같이 IPhone의 생성자를 통해서 의존관계에 있는 객체인 watch를 주입할 수 있음 

package test;

public class IPhone implements Phone{
	private Watch watch; //객체 맴버변수 이기 때문에 의존관계 -< 의존성 주입(DI)이 필요한 상태 
	private int number;
	
	public IPhone() {
		System.out.println("아이폰 객체 생성완료");
	}
	// 생성자 인젝션 
	  public IPhone(Watch watch) { //외부에서 받아온걸로 생성자 new 
		System.out.println("아이폰 객체 생성 완료22");
		this.watch=watch;
	}
	public IPhone(Watch watch, int number) { //외부에서 받아온걸로 생성자 new 
		System.out.println("아이폰 객체 생성 완료33");
		this.watch=watch;
		this.number=number;
	}
	@Override
	public void powerOn() {
		System.out.println("아이폰 전원 ON");
		// TODO Auto-generated method stub
		
	}
	@Override
	public void powerOff() {
		System.out.println("아이폰 전원 OFF");
		// TODO Auto-generated method stub
		
	}
	@Override
	public void volumeUp() {
		System.out.println("아이폰 소리 ++");
		// TODO Auto-generated method stub
		
	}
	@Override
	public void volumeDown() {
		System.out.println("아이폰 소리 --");
		// TODO Auto-generated method stub
		
	}
}

 

설정파일에서 워치를 "aw", "bw"로 생성

사용하지 않는 워치는 사용할때만 생성되게 하기위해서 lazy-inite=true로 설정

 

constructor-arg태그의 ref 속성을 사용하여 주입할 객체를 전달 받고,

주입할 객체는 <bean>을 통해서 생성되여야 함.

설정 파일에서 기본 데이터 타입이나 String타입이라면 ref 대신 value를 사용 

<?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="ap" class="test.IPhone">
		<constructor-arg ref="aw" /><!-- ref속성을 통해서 주입할 객체를 받음 -->
		<!-- 생성자 injection을 무엇을 하느냐에 따라서 달라짐 -->
		<constructor-arg value="9890" />
	</bean>

	<bean id="aw" class="test.AppleWatch" lazy-init="true" />
	<bean id="bw" class="test.GalaxyWatch" lazy-init="true" />

</beans>

 

클라이언트에 하기와 같이 수정 후 실행

package test;

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

public class Client {
	public static void main(String[] args) {
		 //1. Spring 컨테이너를 동작시킬 수 있도록 코드작성 
		 AbstractApplicationContext factory=new GenericXmlApplicationContext("applicationContext.xml");
		 
		//2. Spring 컨테이너야, 나 폰 객체가지고싶어! 
		// = Lookup		
		 Phone phone=(Phone)factory.getBean("ap");

		 phone.powerOn();
		 phone.volumeUp();
		 phone.volumeDown();
		 phone.powerOff();
		 
		//3. 컨테이너 연결 해제 
		factory.close();
	}
}

 

아이폰 + 애플워치가 나오는걸 확인할 수 있음 

 

이처럼 참조할 객체를 변경하고 싶다면 클라이언트가 아닌 설정파일에서 수정이 가능 

 


1) 수정자 주입 (Setter 주입, Setter Injection) 

일반적으로 생성자 주입보다 setter 주입을 더 많이 사용함 

 

Phone 객체에 주입할 객체(watch)를 변수화 시켜서 setter을 생성 

package test;

public class IPhone implements Phone{
	private Watch watch; //객체 맴버변수 이기 때문에 의존관계 -< 의존성 주입(DI)이 필요한 상태 
	private int number;
	
	//생성자
	public IPhone() {
		System.out.println("아이폰 객체 생성완료");
	}
	
	//get & set
	public Watch getWatch() {
		return watch;
	}
	public void setWatch(Watch watch) {
		this.watch = watch;
	}
	public int getNumber() {
		return number;
	}
	public void setNumber(int number) {
		this.number = number;
	}
	@Override
	public void powerOn() {
		System.out.println("아이폰 전원 ON : " + this.number);
		
	}
	@Override
	public void powerOff() {
		System.out.println("아이폰 전원 OFF");
		
	@Override
	public void volumeUp() {
		System.out.println("아이폰 소리 ++");
		
	}
	@Override
	public void volumeDown() {
		System.out.println("아이폰 소리 --");
		
	}
}

 

생성자 주입 방식와 다르게 property 태그를 사용 

<?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="ap" class="test.IPhone">
		<property name="watch" ref="aw"></property>
		<property name="number" value="9890"></property>
	</bean>

	<bean id="aw" class="test.AppleWatch" lazy-init="true" />
	<bean id="bw" class="test.GalaxyWatch" lazy-init="true" />

</beans>

 

 

※ 생성자 주입(왼쪽)과 setter 주입(오른쪽)이 객체 생성 순서가 차이가 있다?!?! 

생성자는 워치 객체가 먼저 생성되고 아이폰 

setter는 아이폰이 먼저 생성되고 워치 


p 네임스페이스 

 

setter 인젝션을 수행할때, p네임 스페이스와 함께 활용

setter 주입을 조금 더 간편하게 사용 가능 

 

왼쪽하단의 Namespaces 탭을 누르고 p라는 태그를 클릭 후 다시 Source로 이동 

xmlns:p="http://www.springframework.org/schema/p"

상기 코드가 추가 되었는데 만약 Namespaces 탭을 찾을 수 없다면 코드만 추가해두면 됨 

 

p 태그를 사용하여 조금 더 간략하게 표현이 가능함

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

<?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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="ap" class="test.IPhone" p:watch-ref="aw" p:number="9890"></bean>

	<bean id="aw" class="test.AppleWatch" lazy-init="true" />
	<bean id="bw" class="test.GalaxyWatch" lazy-init="true" />

</beans>

컬렉션 사용 

 

1. List 주입 

 

package test;

import java.util.List;
import java.util.Map;

public class TestBean {

	private List<String> datas; //기본생성자는 생성자를 따로 작성하지 않으면 원래 존재한다

	public List<String> getDatas() {
		return datas; 
	}
	public void setDatas(List<String> datas) {
		this.datas = datas; 
	}
}

 

설정 파일에서 리스트로 추가 - 리스트 안에 값은 value로! 

<?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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">



	<bean id="ap" class="test.IPhone" p:watch-ref="aw" p:number="9890"></bean>

	<bean class="test.TestBean" id="test">
 		<property name="datas">
 			<list>
 				<value>바나나</value>
 				<value>키위</value>
 				<value>포도</value>
 			</list>
 		</property>
 	</bean>

	<bean id="aw" class="test.AppleWatch" lazy-init="true" />
	<bean id="bw" class="test.GalaxyWatch" lazy-init="true" />

</beans>

 

클라이언트에서 리스트 호출 

package test;

import java.util.List;

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

public class Client {
	public static void main(String[] args) {
		 //1. Spring 컨테이너를 동작시킬 수 있도록 코드작성 
		 AbstractApplicationContext factory=new GenericXmlApplicationContext("applicationContext.xml");
		// 2. Spring 컨테이너에게 객체요청
			TestBean test=(TestBean)factory.getBean("test");
			List<String> list=(List<String>) test.getDatas();
			for(String v:list) {
				System.out.println(v);
			}
			
			// 3. 컨테이너 연결해제
			factory.close();
	}
}


2. Set 주입 

 

package test;

import java.util.Set;

public class TestBean {

	private Set<String> set; 
	public Set<String> getDatas() {
		return set; 
	}

	public void setSet(Set<String> set) {
		this.set = set; 
	}
}
<?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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">



	<bean id="ap" class="test.IPhone" p:watch-ref="aw" p:number="9890"></bean>

	<bean class="test.TestBean" id="test">
		<property name="set">
			<set>
				<value>바나나</value>
				<value>바나나</value>
				<value>키위</value>
			</set>
		</property>
	</bean>

	<bean id="aw" class="test.AppleWatch" lazy-init="true" />
	<bean id="bw" class="test.GalaxyWatch" lazy-init="true" />

</beans>

 

클라이언트에서 Set 호출 

package test;

import java.util.Set;

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

public class Client {
	public static void main(String[] args) {
		 //1. Spring 컨테이너를 동작시킬 수 있도록 코드작성 
		 AbstractApplicationContext factory=new GenericXmlApplicationContext("applicationContext.xml");
		// 2. Spring 컨테이너에게 객체요청
			TestBean test=(TestBean)factory.getBean("test");
			Set<String> set=(Set<String>) test.getDatas();
			for(String v:set) {
				System.out.println(v);
			}
			
			// 3. 컨테이너 연결해제
			factory.close();
	}
}

 

set안에 바나나 value가 두개 있었는데 한개만 출력 됨 

 


3. Map 주입 

 

package test;

import java.util.Map;

public class TestBean {

	private Map<String,String> datas;

	public Map<String, String> getDatas() {
		return datas; 
	}
	public void setDatas(Map<String, String> datas) {
		this.datas = datas; 
	}
}
<?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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">



	<bean id="ap" class="test.IPhone" p:watch-ref="aw" p:number="9890"></bean>

	<bean id="tb" class="test.TestBean">
		<property name="datas">
			<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>

	<bean id="aw" class="test.AppleWatch" lazy-init="true" />
	<bean id="bw" class="test.GalaxyWatch" lazy-init="true" />

</beans>

 

클라이언트에서 Map 호출 

package test;

import java.util.Iterator;
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) {
		 //1. Spring 컨테이너를 동작시킬 수 있도록 코드작성 
		 AbstractApplicationContext factory=new GenericXmlApplicationContext("applicationContext.xml");
		// 2. Spring 컨테이너에게 객체요청
			TestBean test=(TestBean)factory.getBean("tb");
			Map<String, String> map= test.getDatas();
			Iterator<String> itr=map.keySet().iterator();
			while(itr.hasNext()) {
				String key=itr.next();
				System.out.println(key+" : "+map.get(key));
			}
			
			// 3. 컨테이너 연결해제
			factory.close();
	}
}

 

728x90
반응형