구리

TIL_210615_스프링 XML 설정 및 속성, 의존성 관리 종류 본문

SPRING FRAMEWORK

TIL_210615_스프링 XML 설정 및 속성, 의존성 관리 종류

guriguriguri 2021. 6. 15. 21:28

목차

스프링 설정 파일 생성

스프링 컨테이너 
스프링 XML 설정
<import>
<bean>
<bean> 요소 속성 (init,destory,lazy - method, scope)
스프링 의존성 관리 방법 (DL, DI)
생성자 인젝션
private 변수의 setter 를 이용한 의존성 주입

 

 

 

스프링 설정 파일 생성

스프링 컨테이너가 관리할 클래스들이 등록된 XML 문서 설정 파일이 필요합니다.

 

BoardWeb 프로젝트의 src/main/resources 소스 폴더 선택 => [New] => [Other] 클릭후 Spring - Spring Bean Configuration File 선택 

File name에 applicationContext 입력 후 (Next 누르지 않고)  Finish 클릭시 스프링 설정 파일 생성 완료됩니다.

이때 기본으로 <beans> 루트 element와 namespace 관련 설정들이 추가되어 제공됩니다.

<?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">

</beans>

 

 

스프링 컨테이너 구동 및 테스트

( 아래 예제로 만들 Tv 객체 테스트 클라이언트)

TvUser.java
package polymorphism;

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

public class TvUser {

	public static void main(String[] args) {
		// 1. Spring Container 구동
		AbstractApplicationContext factory = new GenericXmlApplicationContext("applicationContext.xml");		
	}
}

위 코드를 실행하면 콘솔창은 다음과 같이 뜨는데 우선 클래스 경로에 있는 applicationContext.xml 파일을  로딩한다는 메세지가 가장 먼저 출력되며

다음으로 GenericXmlApplcationContext 객체가 생성되어 스프링 컨테이너가 구동되었다는 메세지가 출력된다.

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@6a6824be: 
startup date [Tue Jun 15 20:30:56 KST 2021]; root of context hierarchy

 

TV 객체를 스프링 컨테이너 구동 후 Main 클래스에서 getBean() 메서드를 이용해 요청하도록 한다.

 

SamsungTV.java
package polymorphism;

public class SamsungTV implements TV {
	
	public SamsungTV() {
		System.out.println("===> SamsungTV 객체 생성");
	}
    
    @Override
	public void powerOn() {
		System.out.println("SamsungTV---전원 켜기");
		
	}

	@Override
	public void powerOff() {
		System.out.println("SamsungTV---전원 끄기");
		
	}

	@Override
	public void volumeUp() {
		System.out.println("SamsungTV---소리 높이기");
		
	}

	@Override
	public void volumeDown() {
		System.out.println("SamsungTV---소리 낮추기");
		
	}
}


TVUser.java
package polymorphism;

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

public class TvUser {

	public static void main(String[] args) {
		// 1. Spring Container 구동
		AbstractApplicationContext factory = new GenericXmlApplicationContext("applicationContext.xml");		
		
		// 2. Spring Container로부터 필요한 빈 객체 요청(lookUp) , DL
		TV tv = (TV)factory.getBean("tv");
		
		tv.powerOn();
		tv.powerOff();
		tv.volumeUp();
		tv.volumeDown();
		
		// 3. 자원 해제
		factory.close();
		
		
		// 결합도를 낮추기 위해선 TV 인터페이스 생성하여 다형성 이용
		
	}

}
<?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="tv" class="polymorphism.SamsungTV">
		
	</bean>

</beans>

실행결과 
스프링 컨테이너 동작 순서

① TVUser 클라이언트가 스프링 설정 파일을 로딩하여 컨테이너 구동

② 스프링 설정 파일에 <bean> 등록된 SamsungTV 객체 생성

③ getBean() 메소드로 이름이 'tv'인 객체 요청(LookUp)

④ SamsungTV 객체 반환 

 

여기서 중요한 점은 만약 SamsungTV에서 LgTV 클래스를 생성하여 변경한다해도 applcationContext.xml 파일만 수정하면 되기에 

TvUser 클라이언트소스를 수정하지 않고도 동작하는 TV를 변경할 수 있어 유지 보수가 더 편해졌다는 점이다

 

 

 

스프링 컨테이너 

BeanFactory / ApplicationContext가 있지만 실제로는 ApplicationContext만 사용하는 정도인데 이유는 BeanFactory 보다 많은 기능을 제공하고 웹 애플리케이션 개발에도 지원하기 때문에 대부분 스프링 프로젝트는 ApplicationContext 유형의 컨테이너를 사용한다.

(참고로 ApplicationContext 는 여러개 생성 가능하다)

 

ApplicationContext 구현한 대표적인 클래스

구현 클래스 기능
GenericXmlApplicationContext 파일 시스템이나 클래스 경로에 있는 XML 설정 파일을 로딩하여 구동하는 컨테이너
XmlWebApplicationContext 웹 기반의 스프링 애플리케이션 개발시 사용하는 컨테이너 
(우리가 직접 생성하지 않는 컨테이너)

 

 

스프링 XML 설정

1. <bean> root element

스프링 컨테이너는 <bean> 저장소에 해당하는 XML 설정 파일을 참조해 <bean>의 생명주기를 관리하고 여러 가지 서비스를 제공한다.

따라서 스프링 프로젝트 전체에서 가장 중요한 역할을 담당하며, 이 설정 파일을 정확히 작성하고 관리해야 한다.

스프링 설정 파일 이름은 무엇이든 상관없지만 <beans>를 root element로 사용해야 하며 <beans> element 시작 태그에 네임스페이스를 비롯한 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"
	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">
</beans>

STS를 이용해 만든 스프링 설정 파일에는 beans 네임스페이스가 기본 네임스페이스로 선언되어 있으며, spring-beans.xsd 스키마 문서가 schemaLocation으로 등록되어 있다. 따라서 <bean>, <import>, <alias>, <description> 등 4개의 요소를 자식 요소로 사용할 수 있는데 실제로는

<bean>, <import> 정도가 사용된다.

 

 

<import>

<import> 태그를 이용해 여러 스프링 설정 파일을 포함함으로써 한 파일에 작성하는 것과 같은 효과를 낸다

 

<bean>

객체를 위한 이름을 지정하 때 사용하는 속성이 id로 반드시 스프링 컨테이너가 생성한 개체들 사이에서 유일해야 한다 (값이 중복되어서도 숫자, 특수문자, 공백도 안된다)

 

예시

<bean id="sony" class="polymorphism.SonySpeaker"></bean>
// 1번만 사용하는 객체라면 id값 생략도 가능

 

<bean> 요소 속성

1) init-method

스프링 컨테이너는 디폴트 생성자만 호출하기에 init-method 사용하여 멤버변수 초기화 작업을 진행한다

해당 메소드 실행 시점은 클래스 이용하여 객체 생성 후 해당 객체가 getBean()에 의해 반환되기 직전으로 초기화 직전에 호출된다는 의미이다

(아래와 같은 코드 작성시 SamsungTV 클래스에는 initMethod() 메소드가 당연히 정의되어 있어야 한다)

<bean id="tv" class="polymorphism.SamsungTV" init-method="initMethod" />

 

 

2) destory-method

스프링 컨테이너가 객체 삭제 직전 호출될 임의 메소드 지정 

<bean id="tv" class="polymorphism.SamsungTV" destroy-method="destroyMethod" />

 

3) lazy-init

ApplicationContext는 컨테이너 구동되는 시점에 스프링에 설정된 <bean>들이 생성되는 즉시 로딩 방식으로 자주 사용되지 않는 빈들은 메모리를 많이 차지하게 된다.

따라서 해당 <bean>이 사용되는 시점에 객체를 생성해주는 lazy-init 속성을 제공한다. (클라이언트 요청 시점에 생성하여 메모리 관리에 효율적이다)

<bean id="tv" class="polymorphism.SamsungTV" lazy-init="true" />

 

4) scope 속성

기본값은 singleton으로 속성을 생략하게 되면 기본값으로 적용된다. scope 속성값이 prototype일 경우 해당 <bean>이 요청될 때마다 매번 새로운 객체를 생성한다.

<bean id="tv" class="polymorphism.SamsungTV" scope=["singleton" | "prototype" ] />

 

 

스프링 의존성 관리 방법

DL (Dependency LookUp)

컨테이너가 애플리케이션 운용에 필요한 객체를 생성하고 클라이언트는 컨테이너가 생성한 객체를 검색(Lookup)하여 사용하는 방식

실제 애플리케이션 개발 과정에서는 사용하지 않음

 

DI(Dependency Injection)

객체 사이의 의존관계를 스프링 설정 파일에 등록된 정보를 바탕으로 컨테이너가 자동으로 처리

다시 Setter 메소드를 기반으로 한 세터 인젝션, 생성자를 기반으로 하는 생성자 인젝션으로 나뉨

 

 

생성자 인젝션 예시

더보기
SonySpeaker.java
package polymorphism;

public class SonySpeaker implements Speaker {

	public SonySpeaker() {
		System.out.println("SonySpeaker 객체 생성");
	}

	@Override
	public void volumeUp() {
		System.out.println("SonySpeaker 소리 크기 증가 !");
		
	}

	@Override
	public void volumeDown() {
		System.out.println("SonySpeaker 소리 크기 감소...");
		
	}
}
SamsungTV.java
package polymorphism;

public class SamsungTV implements TV {
	private Speaker speaker;
	
	public SamsungTV() {
		System.out.println("SamsungTV (1) 객체 생성");
	}

	public SamsungTV(SonySpeaker speaker) {
		System.out.println("SamsungTV (2) 객체 생성");
		this.speaker = speaker;
	}

	@Override
	public void powerOn() {
		System.out.println("SamsungTV---전원 켜기 ");
		
	}

	@Override
	public void powerOff() {
		System.out.println("SamsungTV---전원 끄기");
		
	}

	@Override
	public void volumeUp() {
		speaker.volumeUp();
		
	}

	@Override
	public void volumeDown() {
		speaker.volumeDown();
		
	}
}


<?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="tv" class="polymorphism.SamsungTV" p:speaker-ref="apple" p:price="250000">	
	</bean>
	
	<bean id="tv" class="polymorphism.SamsungTV">
		<constructor-arg ref="sony"></constructor-arg>
	</bean>
	
	<bean id="sony" class="polymorphism.SonySpeaker"></bean>
	<bean id="apple" class="polymorphism.AppleSpeaker"></bean>
</beans>

위 처럼 코드 작성 후 Main 클래스에서 실행하면 결과는 위와 같은데 생성자 인젝션으로 의존성 주입될 SonySpeaker가 먼저 객체 생성되었으며,

 SonySpeaker 객체를 매개변수로 받아들이는 생성자를 호출하여 객체를 생성하였다.

 

생성자 인젝션을 사용할 경우

 // 여러 개의 객체를 전달받는 생성자의 경우 (매개변수 선언 순서대로...)
      <bean ~~~>
            <constructor-arg ref="빈객체id"></constructor-arg>
            <constructor-arg ref="빈객체id"></constructor-arg>
      </bean>


      // 객체와 값을 전달받는 생성자의 경우 (매개변수 선언 순서대로...)
      <bean ~~~>
            <constructor-arg ref="빈객체id"></constructor-arg>
            <constructor-arg value="값"></constructor-arg>
      </bean>

      // 객체와 값(데이터 타입지정)을 전달받는 생성자의 경우 (매개변수 선언 순서대로...)
      <bean ~~~>
            <constructor-arg ref="빈객체id"></constructor-arg>
            <constructor-arg >
                    <value type="데이터타입">값</value>
            </constructor-arg>
      </bean>

      // 매개 변수 선언 순서와 관계없이 값을 전달할 경우 (index 속성을 이용)  
      // 빈 클래스의 생성자 매개변수가  (값, 객체) 의 순으로 정의 되어 있을 경우,,,,
      <bean ~~~>
            <constructor-arg index="1" ref="빈객체id"></constructor-arg>
            <constructor-arg index="0" value="값"></constructor-arg>
      </bean>

 

private 변수의 setter 를 이용한 의존성 주입

1) <property> 태그를 이용

<beans ~~~>
      <bean ~~~~>
              <property name="속성명(private 변수명)"  ref="빈객체id" ></property>
              <property name="속성명(private 변수명)"  value="값" />
      </bean>
</beans>

2) p Namespace를 이용

<beans ~~
            xmlns:p="http://www.springframework.org/schema/p"  >    // 반드시 필요
      <bean  ~~~~    p:변수명-ref="빈객체id"    p:변수명="값"   >
      </bean>
</beans>