Spring

DI (Dependency Injection) 의존 주입

본이qq 2022. 9. 14. 14:56

-src/main/java 폴더에 

-1. 실행할 MainClass

-2. Battery 인터페이스 / Battery 인터페이스를 구현할 클래스 ChargeBattery, NormalBattery 2개 생성 

-3. ElectronicCar, ElectronucRadio 클래스 생성

 

 

 

- Battery 인터페이스

package com.ezen.battery;

public interface Battery {

	public int getBatteryValue();
	
}

 

- NormalBattery.java

package com.ezen.battery;

public class NormalBattery implements Battery{

	@Override
	public int getBatteryValue() {
		return 0;
	}

}

-> Battery 인터페이스의 getBatteryValue 메소드 오버라이딩 

 

 

-ChargeBattery.java

package com.ezen.battery;

public class ChargeBattery implements Battery {

	@Override
	public int getBatteryValue() {
		return 0;
	}
	
	public void charge(int value) {
		
	}

}

-> Battery 인터페이스의 getBatteryValue 메소드 오버라이딩 

 

 

 

 

 

 

-ElectronicCar.java

package com.ezen.toy;

import com.ezen.battery.Battery;
import com.ezen.battery.NormalBattery;

public class ElectronicCar {

	private Battery bat; //인터페이스 레퍼런스 변수, - NormalBattery 또는 ChargeBattery 인스턴스가 저장될 변수 
	
	public ElectronicCar() {
		//생성자에서 노멀배터리를 멤버변수의 초기값으로 대입하고 시작합니다. 
		bat = new NormalBattery();
		//인터페이스멤버 변수에 battery를 임플리먼트한 클래스를 대입합니다. 
	}
}

//이 장난감은 배터리가 출시당시 탑재(내장)되어서 교체가 불가능한 상태로 판매되는 형태입니다.

-> 멤버변수 Battery 생성 

-> ElectronicCar 객체 생성시 Battery 멤버변수에 NormalBattery 인스턴스를 대입한다. 

 

 

 

-ElectronicRadio.java

package com.ezen.toy;

import com.ezen.battery.Battery;

public class ElectronicRadio {

	private Battery bat;
	
	//생성자에서 배터리가 초기화되는데, 그 초기값이 생성자의 전달인수로 전달되어야 하는 형태입니다, 
	public ElectronicRadio(Battery bat) {
		this.bat = bat;
	}
	public void setBattery(Battery battery) {
		this.bat = battery;
	}//추후 배터리를 새로 교체할 수 있는 기능이 있습니다. 
}

//구매와 동시에 동봉 또는 별도 구입한 새 배터리를 장착할 수 있는 기능이 있습니다.

-> 위 ElectronicCar 클래와 달리 ElectronicRadio 클래스는 생성시에 Battery 객체를 필요로한다. 

-> 위 ElectronicCar 클래스와 달리 setBattery(Battery battery) 메소드를 통해 Battery 멤버 변수에 새로운 값을 대입할 수 있다. 

-> 즉, 구입(객체 생성)시 배터리가 장착 / 추후에 교체할 수 있다. 

 

 

 

 

 

-가장 중요한 MainClass.java

package com.ezen;

import org.springframework.context.support.GenericXmlApplicationContext;

import com.ezen.battery.ChargeBattery;
import com.ezen.battery.NormalBattery;
import com.ezen.toy.ElectronicCar;
import com.ezen.toy.ElectronicRadio;

public class MainClass {

	public static void main(String[] args) {
		//일반적인 사용예
		
		//배터리가 장착된 상태로 판매되는 일체형. 객체생성 하나만으로 사용이 가능합니다. 
		ElectronicCar carToy1 = new ElectronicCar();
        
        //ElectronicRadio radioToy = new ElectronicRadio(); //에러
		//생성자에 배터리 객체가 전달되어야, 매개변수가 있는 생성자가 실행되므로 위는 에러입니다. 
		NormalBattery nbatt1 = new NormalBattery();
		ChargeBattery cbatt1 = new ChargeBattery();
		ElectronicRadio radioToy1 = new ElectronicRadio(nbatt1);
		//생성자에 배터리 객체를 전달해주면 정상 생성, 이렇게 객체 생성시에 다른 객체의 존재 및 생성자로의 전달이 필수인 상태! 
		//객체생성이 다른 객체에 의존하고 있는 상태! 이를 객체 의존이라고 부릅니다. 
		//그리고 필요 객체를 생성자의 전달인수로 넣어주는 것을 의존주입(Dependency Injection)이라고 부릅니다. 
		
		GenericXmlApplicationContext ctx 
		= new GenericXmlApplicationContext("classpath:applicationContext.xml");
		
		ElectronicCar carToy2 = ctx.getBean("car", ElectronicCar.class);
		ElectronicRadio radioToy2 = ctx.getBean("radio",ElectronicRadio.class);
		radioToy2.setBattery(nbatt1);
		//스프링 프레임워크에서의 클래스 사용이 약간 업그레이드되어 조금 간편해졌습니다. 
		

	}

}

-> 첫째줄부터 코드를 하나하나 뜯어보면, 

1) ElectronicCar carToy1 = new ElectronicCar(); --> ok 

  ElectronicCar 클래스는 생성자에 매개변수를 필요로 하지 않으니 이대로 객체 생성이 가능하지만, 

  ElectronicRadio radioToy = new ElectronicRadio(); --> x

  ElectronicRadio 클래스는 생성자에 매개변수(Battery 인터페이스를 구현하는 클래스)를 필요로 하므로, 에러이다.

 

  NormalBattery nbatt1 = new NormalBattery();

  ChargeBattery cbatt1 = new ChargeBattery();

  ElectronicRadio radioToy1 = new ElectronicRadio(nbatt1);

 

-->위와 같이 Battery 인터페이스를 구현하는 클래스의 객체 생성을 하고, ElectronicRadio의 생성자 매개변수에 넣어주면 ok이다. 

     nbatt1을 보내줘도 되고, cbatt1을 보내줘도 Ok이다. 

 

Dependency Injection(DI) 의존주입 
-위와 같이 필요 객체를 생성자의 전달인수로 넣어주는 것을 의존 주입이라고 한다. 

 

-만약 중간에 Battery 인터페이스를 두지 않고 직접 ElectronicRadio 생성자의 매개변수로 NormalBattery 객체를 전달하게 되면 어떻게 될까? (NormalBattery와 ChargeBattery 클래스는 Battery 인터페이스를 구현하지 않는 독립적인 클래스라고 가정)

package com.ezen.toy;

public class ElectronicRadio {

	private NomalBattery nbatt1;
	
	public ElectronicRadio(NormalBattery nbatt1) {
		this.nbatt1 = nbatt1;
	}
	public void setBattery(ChargeBattery nbatt2) {
		this.nbatt1 = nbatt2;
	}//추후 배터리를 새로 교체할 수 있는 기능이 있습니다. 
}

---> 위와 같이 (NormalBattery, ChargeBattery) 클래스와 ElectronicRadio 클래스 객체간의 의존도가 훨씬 높아진다. 

---> 만약 나중에 장착될 혹은 교체될 배터리가 달라진다면 코드 수정이 불가피하다. 

---> 따라서 객체간의 결합도를 약하게 하기 위해 중간에 Battery 인터페이스를 둔다. 

 

 

 

 

 


GenericXmlApplicationContext
- XML 파일로부터 정보를 읽어와 객체를 생성하고 초기화 
- 스프링은 각각의 객체를 연결하고 조립하는 역할을 한다.
- 스프링 컨테이너가 생성해서 보관하는 객체를 빈(Bean)객체라고 하며 자바의 객체와 동일하다.  
-getBean() 메서드를 이용하여 빈(Bean) 객체를 return 받는다.
-Bean 객체를 미리 생성해놓고 필요시 꺼내쓴다는것은, 싱글톤 방식과 같다. 
-만약 다른 인스턴스를 생성하고 싶다면, id만 달리해서 Bean객체를 생성하면 된다. 
-ApplicationContext는 빈 객체의 생성, 초기화, 보관, 제거 등을 관리하는데 이런 이유로 '컨테이너'라고 부른다. 

 

->src/main/resources 폴더 아래 xml 파일에 Bean 객체를 관리한다. 

->자바 객체 생성 처럼 NormalBattery bt = new NormalBattery(); -> new 를 사용하여 객체를 생성하지 않고 

   getBean() 메서드를 사용한다. 

 

 

-applicationContext.xml 파일 

<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 class="com.ezen.battery.NormalBattery" id="nBattery"></bean>
		<bean class="com.ezen.battery.ChargeBattery" id="cBattery"></bean>
		
		<bean id="car" class="com.ezen.toy.ElectronicCar"></bean>
		
		<bean id="radio" class="com.ezen.toy.ElectronicRadio">
			<constructor-arg ref="cBattery"></constructor-arg><!-- 의존 주입 - 객체 조립 -->
		</bean>
		<!-- 클래스의 생성자가 다른 클래스를 매개변수로 갖고, 해당 객체가 전달되어야 생성자 실행이 가능하면, 
		이는 클래스가 다른 클래스에 의존하고 있다. 라고 얘기합니다. 그리고 의존에 해당하는 객체를 위와 같이 Constructor-arg를 
		이용해서 채워주는 것을 의존 주입이라고 말합니다. 통틀어 객체 조립이라고 표현합니다. -->
</beans>

 

 

-> getBean 메소드를 이용하여 객체 생성

GenericXmlApplicationContext ctx 
		= new GenericXmlApplicationContext("classpath:applicationContext.xml");
		
ElectronicCar carToy2 = ctx.getBean("car", ElectronicCar.class);
ElectronicRadio radioToy2 = ctx.getBean("radio",ElectronicRadio.class);

 

'Spring' 카테고리의 다른 글

빌드 자동화 도구 Maven vs. Gradle  (0) 2022.09.14
Spring MVC 와 Spring Boot  (0) 2022.09.14
DI 의존객체 주입 -> @Autowired  (0) 2022.09.14
DI 의존주입 & Bean 생성과 사용  (0) 2022.09.14