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();
}
}
'Spring' 카테고리의 다른 글
[Spring] AOP 관점 지향 프로그래밍, Advice 동작시점 (0) | 2022.09.16 |
---|---|
[Spring] DB 연결 (MVC패턴) (0) | 2022.09.16 |
[Spring] 어노테이션 (@, annotation) (0) | 2022.09.15 |
[Spring] Spring Framwork 란? (0) | 2022.09.14 |
[Spring] Eclipse Spring 설치 및 초기설정 (0) | 2022.09.13 |