라이브러리는 도서관 아닌가요

DI 2 - xml 파일로 Spring DI 지시서 작성 본문

Java/DI

DI 2 - xml 파일로 Spring DI 지시서 작성

veryhi 2021. 12. 14. 07:09

 

* Spring Tool 3 (Add-On)이 설치되고 관련 플러그인이 등록돼 있어야 합니다.

 

순수 Java를 벗어나 spring의 도움을 얻어 xml 파일로 DI를 해결해보자.

 

앞선 포스트에서 구현한 내용을 참고하여 진행한다. 

( DI 1 : https://verycrazy.tistory.com/34?category=1027221 )

// myPackage.Keyboard

interface Keyboard{
     String getKeyboardBrand();
}
// myPackage.KoreaKeyboard
public class KoreaKeyboard implements Keyboard{
     public String getKeyboardBrand(){
         return = "한국산 키보드";
     }
}
// myPackage.AmericaKeyboard
public class AmericaKeyboard implements Keyboard{
     public String getKeyboardBrand(){
         return = "미국산 키보드";
     }
}
// myPackage.Laptop
public class Laptop{
     Keyboard keyboard;

     public Keyboard getKeyboard(){
          return keyboard;
     }

     public void setKeyboard(Keyboard keyboard){
          this.keyboard = keyboard;
     }

     public String showInputBrand(){
         return "연결된 키보드= " + keyboard.getKeyboardBrand();
     }
}
public class Main{
     public static void main(String[] args){
          Keyboard aKeyboard = new KoreaKeyboard();
          // Keyboard aKeyboard = new AmericaKeyboard();

          Laptop aLaptop = new Laptop(); 
          aLaptop.setKeyboard(aKeyboard); // 주입

          System.out.println(aLaptop.showInputBrand()); // "연결된 키보드= 한국산 키보드"
     }
}

 

위의 보여지는 코드와 같이,

 

DI 지시서를 작성하는 것은 설정자 메서드(setter)와 깊은 관련이 있다.

 

어렵게 접근할 것 없이 Java 상에서 의존성이 생성되는 저 부분( new KoreaKeyboard(); )을 지우고,

 

지시서에 그 객체 생성을 의존하자 것이다.

 

그렇다면 그 관련 코드가 xml에 의해 대체되어 위치하게 된다.

 

참고로 생성되는 객체는 IoC 컨테이너라는 곳에서 관리 된다.

 

myPackage 패키지 내에,

 

Spring Bean Configuration File 생성하기로

 

xml 설정 파일을 만든다.

 

# myPackage/setting.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">
	
	<!-- KoreaKeyboard 타입인 aKeyboard가 해당 경로에 존재하니 참조해라 -->
	<bean id="aKeyboard" class="myPackage.KoreaKeyboard" />

	<!-- Laptop 타입인 aLaptop이 해당 경로에 존재하니 참조해라 -->
	<bean id="aLaptop" class="myPackage.Laptop">
		<!-- Keyboard aKeyboard = new KoreaKeyboard(); -->
		<!-- aLaptop.setKeyboard(aKeyboard); -->
		<property name="keyboard" ref="aKeyboard"></property>
	</bean>

</beans>

<property> 태그는 '주석처리된 위의 Java 코드'와 같은 역할을 수행한다.

 

(정확하게는 Spring이 지시서를 보고 수행해준다.)

 

중요한 것은 실질적인 injection을 수행해주는 property 내의 name이 "keyboard"로 되어있지만,

 

사실은 "setKeyboard"로 묵시적 변환이 일어난다.

 

이것은 약속이니 숙지해둬야 한다.

 

그리고 스프링이 aLaptop의 속성으로 aKeyboard를 사용하고자 하지만,

 

이는 현재 해당 경로의 클래스에 존재하지 않는다.

 

따라서 스프링이 대신 생성하여 의존성을 해결해준다(!)

 

 

 

 

 

.java에서 작성될 코드를 살펴보자.

 

현재 어쩌면 가장 핵심적인 역할을 하는 코드가 한 줄 빠져 있다.

 

바로 아래의 코드이다.

 

(사용하려면 Spring Framework Library의 의존성이 해결돼 있어야 한다. 쌩으로 구현하면 pom.xml을 손 봐야 한다.)

# setting.xml의 이름은 센스껏 지으면 된다.

ApplicationContext context = new ClassPathXmlApplicationContext("setting.xml");

 

코드 상에서 실제로 지시서를 읽어서 관련 객체들을 생성하고 DI를 수행해주는 객체가 바로 저 녀석이다.

 

ApplicationContext는 정확하게 interface다. (역시 자바)

 

해당 interface를 구현하는 클래스 중 하나가 바로 저 ClassPathXmlApplicationContext이다.

 

이외에도,

 

FileSystemXmlApplicationContext ( 로컬 파일 시스템 활용 )

XmlWebApplicationContext ( 웹을 활용 )

AnnotationConfigApplicationContext ( 어노테이션을 활용 )

 

...가 있다.

 

 

 

 

 

해당 코드는 관련 객체를 사용하는 Main.java에 위치해야 한다.

 

위치한 context 아래와 같이 사용할 수 있다.

 

# myPackage/Main.java

package myPackage;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("myPackage/setting.xml");
		
      	// 기존 코드
        // Laptop aLaptop = new Laptop();

        // 변경 1번 or
        // Laptop aLaptop = context.getBean("aLaptop", Laptop.class);
        // 변경 2번 or
        // Laptop aLaptop = context.getBean(Laptop.class);
        // 변경 3번
        // Laptop aLaptop = (Laptop)context.getBean("aLaptop");

        // 끼워넣을 부품 생성 생략, xml을 통해 스프링이 대신 수행
        // Keyboard aKeyboard = context.getBean("aKeyboard", Keyboard.class);
        // 의존성 주입 생략 - xml을 통해 스프링이 대신 수행
        // aLaptop.setKeyboard(aKeyboard);

        // 변경 1번 사용
		Laptop aLaptop = context.getBean("aLaptop", Laptop.class);
		//* if there is no the property tag, the below codes will be needed. 
		//Keyboard aKeyboard = context.getBean("aKeyboard", Keyboard.class);
		//aLaptop.setKeyboard(aKeyboard);
		
		System.out.println(aLaptop.showInputBrand());
	}
}

 

Main.java에서 생성된 객체를 사용하려고 불러낼 때,

 

이름(name)으로 꺼내면 Object 타입으로 반환돼서 꼭 타입 변환(Laptop)을 해줘야 한다. 3번과 같이.

 

반면에 타입으로 꺼내면(2번), 별다른 형변환이 필요없다. 말그대로 타입으로 불러냈으니까.

 

1번처럼 사용하면 더 건드릴 게 없다.

 

유의할 점은 aLaptop은 생성하고 aKeyboard는 생성하지 않아도 된다는 점이다.

 

위의 <property> 태그에서 스프링이 의존성을 해결주려고 하는데

 

객체가 존재하지 않기 때문에 직접 생성한다는 것을 위에서 살펴보았다.

 

 

 

 

Comments