IoC(제어의 역행)

스프링 객체의 생성, 의존관계를 스프링에서 자동으로 관리

의존성(Dependency)는 객체와 객체와의 관계를 의미

 

Dependency Lookup : 컨테이너가 객체를 생성, 클라이언트는 생성한 객체를 검색해서 사용 (실 개발과정 미사용)

Denepdency Injection (Setter/Constructor Inection) : 컨테이너가 직접 객체들 사이에 의존관계를 처리

 - Setter과 Constructor의 공통점 : 멤버변수를 원하는 값으로 설정하는것 목적
 - 결과는 같으므로 어떤방법 쓰던지 상관없음
    단, 코딩컨벤션 따라 한가지로 통일. 대부분은 Setter사용 / Setter메소드 제공되지 않는 클래스만 생성자인젝션

 

생성자 인젝션(Constructor Injection)

 - xml에서 클래스 찾아서 객체생성시, 매개변수 없는 기본생성자를 호출

 - 기본생성자 외에 매개변수를 가지는 다른 생성자 호출하도록 생성할 수 있음

 - 생성자 인젝션을 사용해서, 생성자의 매개변수(예시:sony)로 의존관계에 있는 객체주소 정보 전달가능

 - 예시 : <constructor-arg index="0" ref="apple"></constructor-arg> <constructor-arg index="1" value="2000000"></constructor-arg>

이클립스 자동 생성자 추가

생성하려는 클래스 열고 > alt + shift + s > Generate Constructor using Fields> 초기화할 멤버변수 선택후 OK

 

 

src/main/java/polymorphsim/SonySpeaker.java

package polymorphsim;

public class SonySpeaker {
	public SonySpeaker() {
		System.out.println("===> SonySpeaker 객체 생성");
	}
	public void volumeUp() {
		System.out.println("SonySpeaker---소리 울린다.");
	}
	public void volumeDown() {
		System.out.println("SonySpeaker---소리 내린다.");
	}
}

src/main/java/polymorphsim/SamsungTV.java

package polymorphsim;

public class SamsungTV implements TV{
	private SonySpeaker speaker;
	private int price;

	public SamsungTV() {
		System.out.println("===> SamsungTV(1) 객체생성");
	}
	public SamsungTV(SonySpeaker speaker) {
		System.out.println("===> SamsungTV(2) 객체생성");
		this.speaker=speaker;
	}
	
	public SamsungTV(SonySpeaker speaker, int price) {
		System.out.println("===> SamsungTV(3) 객체생성");
		this.speaker = speaker;
		this.price = price;
	}
	public void powerOn() {
		System.out.println("SamsungTv --전원 켠다. (가격: "+price+")");
	}
	public void powerOff() {
		System.out.println("SamsungTv --전원 끈다.");
	}
	public void volumeUp() {
		speaker.volumeUp();
	}
	public void volumeDown() {
		speaker.volumeDown();
	}
}

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

	<bean id ="tv" class="polymorphsim.SamsungTV">
		<constructor-arg index="0" ref="sony"></constructor-arg>
		<constructor-arg index="1" value="2000000"></constructor-arg>
	</bean>
	<bean id = "sony" class="polymorphsim.SonySpeaker"></bean>
    
</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@290dbf45: startup date [Tue Jan 04 00:06:47 KST 2022]; root of context hierarchy
===> SonySpeaker 객체 생성
===> SamsungTV(3) 객체생성
SamsungTv --전원 켠다. (가격: 2000000)
SonySpeaker---소리 울린다.
SonySpeaker---소리 내린다.
SamsungTv --전원 끈다.
INFO : org.springframework.context.support.GenericXmlApplicationContext - Closing org.springframework.context.support.GenericXmlApplicationContext@290dbf45: startup date [Tue Jan 04 00:06:47 KST 2022]; root of context hierarchy

 

  • 객체 생성할때, 기본생성자가 아닌, 세번째 SaumsungTV(Speaker speakr, int price) 생성자가 사용됨.
  • bean등록 순서대로 객체를 처리하는데, 생성자 인젝션으로 의존성 주입될 SonySpeaker가 먼저 객체생성SonySpeaker 객체를 매개변수로 받아들이는 생성자를 호출하여 객체 생성
  • <constructor-arg>엘리먼트의 인자로 전달될 데이터가 <bean>인 다른 객체인경우 ref속성, 고정 문자열/정수인경우는 value
  • 생성자 여러개 오버로딩 된 경우, index속성 통해 어떤값이 몇번째 매개변수로 매핑되는지 지정가능. 0부터시작

 

이클립스 자동 인터페이스 생성

생성할 인터페이스의 자식 열고 > alt + shift + T > Extract Interface> 생성할 인터페이스 이름/메소드 선택후 OK

 * 체크박스 전체해제

 

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

	<bean id ="tv" class="polymorphsim.SamsungTV">
		<constructor-arg index="0" ref="apple"></constructor-arg>
		<constructor-arg index="1" value="2000000"></constructor-arg>
	</bean>
	<bean id = "sony" class="polymorphsim.SonySpeaker"></bean>
	<bean id = "apple" class="polymorphsim.AppleSpeaker"></bean>
    
</beans>

자바코드 수정없이, <constructor-arg 의 ref를 "sony"대신 "apple"로 변경하여 AppleSpeaker호출가능

 

<추가 생성/수정한 파일>

(interface) Speaker.java

(class) SonySpeaker.java

(class) AppleSpeaker.java

(class) SamsungTV.java >> 매개변수/멤버변수를 SonySpeaker대신, Speaker로 변경

 


Setter Injection

- Setter메소드 호출해서 의존성 주입을 처리

- 대부분 생성자 주입 보다 setter 주입 사용

- Setter메소드는 스프링 컨테이너가 자동으로 호출, 호출시점은 <bean> 객체 생성 직후
  Setter인젝션 동작하려면, Setter메소드 뿐만 아니라, 기본 생성자도 반드시 필요

- 예시 : <constructor-arg index="0" ref="apple"></constructor-arg> <constructor-arg index="1" value="2000000"></constructor-arg>

 

이클립스 자동 생성자 추가

생성하려는 클래스 열고 > alt + shift + s > Generate Getter and Setters > 초기화할 멤버변수 선택후 OK

 

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

	<bean id ="tv" class="polymorphsim.SamsungTV">
		 <!-- Setter 주입 -->
		 <property name="speaker" ref="apple"></property>
		 <property name="price" value="2000000"></property>
	</bean>
    
	<bean id = "sony" class="polymorphsim.SonySpeaker"></bean>
	<bean id = "apple" class="polymorphsim.AppleSpeaker"></bean>
</beans>

 

  • <property> 엘리먼트사용 필요, name속성값이 호출하려는 메소드이름
    - Setter 메소드 이름 : setSpeaker()
    - name 속성값 : name ="speaker"  (첫문자 대문자로 바꾸고 set붙인 차이..)
  • 생성자주입처럼, Setter 메소드 호출하면서 다른 <bean>객체를 인자로 넘기려면 ref속성, 기본형데이터는 value속성

실행결과

더보기

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@69a10787: startup date [Tue Jan 04 00:37:45 KST 2022]; root of context hierarchy
===> SamsungTV(1) 객체생성
===> AppleSpeaker 객체 생성
===> setSpeaker() 호출
===> setPrice() 호출
===> SonySpeaker 객체 생성
SamsungTv --전원 켠다. (가격: 2000000)
AppleSpeaker-- 소리 올린다.
AppleSpeaker-- 소리 내린다.
SamsungTv --전원 끈다.
INFO : org.springframework.context.support.GenericXmlApplicationContext - Closing org.springframework.context.support.GenericXmlApplicationContext@69a10787: startup date [Tue Jan 04 00:37:45 KST 2022]; root of context hierarchy

 

p 네임스페이스 사용

applicationContext.xml에 추가

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

 

구분 규칙
참조형 변수에 객체 할당 p:변수명-ref = "참조할 객체의 이름이나 아이디"
p:speaker-ref="sony" 
기본형이나 문자형에 직접 값 설정 p:변수명="설정할 값"
p:price='2000000"

 

(p네임스페이스 적용전)

<bean id ="tv" class="polymorphsim.SamsungTV" >
   <property name="speaker" ref="apple"></property>
   <property name="price" value="2000000"></property>
</bean>

 

(p 네임스페이스 적용후)

</bean id="tv" class="polymorphsim.samsungtv" p:speaker-ref="sony" p:price="2000000">

 

 

 sts기능으로 p네임스페이스 추가방법

 


 

컬렉션 객체 설정

스프링에서 컬렉션 매핑과 관련된 엘리먼트들을 지원. 

컬렉션 유형 엘리먼트 비고
java.util.List, 배열 <list> 리스트
java.util.Set <set> 중복미허용
java.util.Map <map> key,value
java.util.Properties <props> key=value

 

List

src/main/java/com/springbook/ioc/injection/CollectionBean.java

package com.springbook.ioc.injection;

import java.util.List;
import java.util.Set;

public class CollectionBean {
	private List<String> addressList;
	public void setAddressList(List<String> addressList) {
		this.addressList = addressList;
	}
	
}

 

 

src/main/resources/applicationContext.xml

	<bean id ="collectionBean" class="com.springbook.ioc.injection.CollectionBean">
		<property name="addressList">
			<list>
				<value>경기도</value>
				<value>서울</value>
			</list>
		</property>
	</bean>

 

--> applicationContext에도 <list>엘리먼트 사용

 

Set (중복미허용)

src/main/java/com/springbook/ioc/injection/CollectionBean.java

package com.springbook.ioc.injection;

import java.util.List;
import java.util.Set;

public class CollectionBean {
	private Set<String> addressList;
	public void setAddressList(Set<String> addressList) {
		this.addressList = addressList;
	}
	
}

 

src/main/resources/applicationContext.xml

	 <bean id ="collectionBean" class="com.springbook.ioc.injection.CollectionBean">
		<property name="addressList">
			<set value-type="java.lang.String">
				<value>서울시 강남구</value>
				<value>서울시 강서구</value>
				<value>서울시 강서구</value>
			</set>
		</property>
	</bean>

--> applicationContext에도 <set value-type="java.lang.String" > 엘리먼트 사용

set이 중복 제거해주므로, 출력결과는 서울시 강남구, 서울시 강서구 2건만 나옴

 

 

main

package com.springbook.ioc.injection;

import java.util.List;
import java.util.Set;
import java.util.Map;
import java.util.Properties;

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

import com.springbook.ioc.injection.CollectionBean;

public class CollectionBeanClient {
	public static void main(String[] args) {
		
		AbstractApplicationContext factory = new GenericXmlApplicationContext("applicationContext.xml");
		CollectionBean bean = (CollectionBean) factory.getBean("collectionBean");
        // List, Set, Map, Properties에 맞게 변경
		Set<String> addressList = bean.getAddressList();
		
		for(String address : addressList) {
			System.out.println(address.toString());
		}
		factory.close();
	}
}

+ Recent posts