DEVLOG

스프링 설정 파일 분리 본문

Spring

스프링 설정 파일 분리

BINTHEWORLD 2022. 6. 6. 15:29

applicationContext.xml에서 빈을 생성하다보면 한 파일에 많은 코드가 집약되어 가독성이 떨어질 수 있다. 이를 방지하기 위해 기능별로 스프링 설정 파일을 분리하고, 스프링 컨테이너 생성을 위해 배열원소로 받는다.

 

기존 applicationContext.xml 파일을 기능별로 나눠 세 개의 파일(appCtx1.xml / appCtx2.xml / appCtx3.xml)로 분리했다고 가정한다. 

이 세 개의 파일을 배열원소로 받아 MainClassUseXMLs.java에서 스프링 컨테이너를 생성해보자.

appCtx1.xml

Dao 객체 생성하고, 이 객체를 매개변수로 받는 Service 객체의 생성자 및 객체 생성

<?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="studentDao" class="ems.member.dao.StudentDao" ></bean>
	
	
	<bean id="registerService" class="ems.member.service.StudentRegisterService">
		<constructor-arg ref="studentDao" ></constructor-arg>
	</bean>
	
	<bean id="modifyService" class="ems.member.service.StudentModifyService">
		<constructor-arg ref="studentDao" ></constructor-arg>
	</bean>
	
	<bean id="deleteService" class="ems.member.service.StudentDeleteService">
		<constructor-arg ref="studentDao" ></constructor-arg>
	</bean>
	
	<bean id="selectService" class="ems.member.service.StudentSelectService">
		<constructor-arg ref="studentDao" ></constructor-arg>
	</bean>
	
	<bean id="allSelectService" class="ems.member.service.StudentAllSelectService">
		<constructor-arg ref="studentDao" ></constructor-arg>
	</bean>
	
</beans>

appCtx2.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="dataBaseConnectionInfoDev" class="ems.member.DataBaseConnectionInfo">
		<property name="jdbcUrl" value="jdbc:oracle:thin:@localhost:1521:xe" />
		<property name="userId" value="scott" />
		<property name="userPw" value="tiger" />
	</bean>
	
	<bean id="dataBaseConnectionInfoReal" class="ems.member.DataBaseConnectionInfo">
		<property name="jdbcUrl" value="jdbc:oracle:thin:@192.168.0.1:1521:xe" />
		<property name="userId" value="masterid" />
		<property name="userPw" value="masterpw" />
	</bean>
	
</beans>

appCtx3.xml

infomation

<?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="informationService" class="ems.member.service.EMSInformationService">
		<property name="info">
			<value>Education Management System program was developed in 2015.</value>
		</property>
		<property name="copyRight">
			<value>COPYRIGHT(C) 2015 EMS CO., LTD. ALL RIGHT RESERVED. CONTACT MASTER FOR MORE INFORMATION.</value>
		</property>
		<property name="ver">
			<value>The version is 1.0</value>
		</property>
		<property name="sYear">
			<value>2015</value>
		</property>
		<property name="sMonth">
			<value>1</value>
		</property>
		<property name="sDay">
			<value>1</value>
		</property>
		<property name="eYear" value="2015" />
		<property name="eMonth" value="2" />
		<property name="eDay" value="28" />
		<property name="developers">
			<list>
				<value>Cheney.</value>
				<value>Eloy.</value>
				<value>Jasper.</value>
				<value>Dillon.</value>
				<value>Kian.</value>
			</list>
		</property>
		<property name="administrators">
			<map>
				<entry>
					<key>
						<value>Cheney</value>
					</key>
					<value>cheney@springPjt.org</value>
				</entry>
				<entry>
					<key>
						<value>Jasper</value>
					</key>
					<value>jasper@springPjt.org</value>
				</entry>
			</map>
		</property>
		<property name="dbInfos">
			<map>
				<entry>
					<key>
						<value>dev</value>
					</key>
					<ref bean="dataBaseConnectionInfoDev"/>
				</entry>
				<entry>
					<key>
						<value>real</value>
					</key>
					<ref bean="dataBaseConnectionInfoReal"/>
				</entry>
			</map>
		</property>
	</bean>
	
</beans>

MainClassUseXMLs.java

기능별로 분리된 위 appCtx.xml 파일들을 배열로 받아 컨테이너 생성

		// 배열로 받기
		String[] appCtxs = {"classpath:appCtx1.xml", "classpath:appCtx2.xml", "classpath:appCtx3.xml"}; 
		GenericXmlApplicationContext ctx = 
				new GenericXmlApplicationContext(appCtxs);

빈(Bean)의 범위

싱글톤(Singleton)

스프링 컨테이너에서 생성된 빈 객체의 경우 동일한 타입에 대해서는 기본적으로 한 개만 생성이 되며, getBean() 메소드로 호출될 때 동일한 객체가 반환된다.

자바 객체 생성시(new ClassName()) 새로운 객체가 계속 생성되어 메모리 낭비가 심하다. 그러나 스프링은 컨테이너 생성시 객체를 호출해서(getBean) 사용하므로 메모리 효율성이 높다.

프로토타입(Prototype) 

싱글톤 범위와 반대의 개념으로, getBean() 메소드로 객체를 참조할 때 새로운 객체를 계속 생성하며, 이를 프로토타입 범위라고 한다.

프로토타입의 경우 개발자는 별도로 설정을 해줘야 하는데, 스프링 설정 파일에서 빈(Bean) 객체를 정의할 때 scope 속성을 명시해주면 된다.

InjectionBean.java

package scope.ex;

public class InjectionBean {

}

DependencyBean.java

생성자와 setter메소드를 활용한 의존성 주입

package scope.ex;

public class DependencyBean {

	private InjectionBean injectionBean;
	
	public DependencyBean(InjectionBean injectionBean) { // 생성자
		System.out.println("DependencyBean : constructor");
		this.injectionBean = injectionBean;
	}
	
	public void setInjectionBean(InjectionBean injectionBean) { // 메소드
		System.out.println("DependencyBean : setter");
		this.injectionBean = injectionBean;
	}
	
}

applicationContext.xml

scope 속성 없이 dependecyBean 객체 생성했으므로, MainClass.java에서 레퍼런스가 다른 두 개의 dependecyBean 객체 호출 시 동일한 메모리 주소의 객체를 가리키므로 한 번만 호출됨

<?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="injectionBean" class="scope.ex.InjectionBean" />
	
	<bean id="dependencyBean" class="scope.ex.DependencyBean">
		<constructor-arg ref="injectionBean" /> <!-- 생성자 생성시 참조객체 -->
		<property name="injectionBean" ref="injectionBean" /> <!-- setter() 메소드 -->
	</bean>
	
</beans>

MainClass.java

package scope.ex;

import org.springframework.context.support.GenericXmlApplicationContext;

public class MainClass {

	public static void main(String[] args) {
		
		GenericXmlApplicationContext ctx = 
				new GenericXmlApplicationContext("classpath:applicationContext.xml");
		
		InjectionBean injectionBean = 
				ctx.getBean("injectionBean", InjectionBean.class);
		
		DependencyBean dependencyBean01 = 
				ctx.getBean("dependencyBean", DependencyBean.class);
		
		DependencyBean dependencyBean02 = 
				ctx.getBean("dependencyBean", DependencyBean.class);
		
		if(dependencyBean01.equals(dependencyBean02)) {
			System.out.println("dependencyBean01 == dependencyBean02"); // 하나의 객체만 생성되어 한 번만 호출됨
		} else {
			System.out.println("dependencyBean01 != dependencyBean02");
		}
		
		
		ctx.close();
		
	}
	
}

아래 실행결과를 보면 동일한 객체를 가리키므로 한 번만 호출되었음을 알 수 있다.

결과

그러나 아래 코드처럼 applicationContext.xml 파일에서 빈 객체에 scope="prototype" 속성을 준다면

<?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="injectionBean" class="scope.ex.InjectionBean" />
	
	<!-- scope="prototype" 속성을 주면 객체 두 개 생성되고, MainClass에서는 두 번 호출됨 -->
	<bean id="dependencyBean" class="scope.ex.DependencyBean" scope="prototype">
		<constructor-arg ref="injectionBean" /> <!-- 생성자 생성시 참조객체 -->
		<property name="injectionBean" ref="injectionBean" />
	</bean>
	
</beans>

아래 실행결과처럼 프로토타입에 의해 getBean() 메소드로 호출할 때마다 새로운 객체가 생성되어 두 번 호출되고,  이 두 객체는 가리키는 주소값이 서로 다름을 알 수 있다. 

결과

 

출처

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC_renew

 

자바 스프링 프레임워크(renew ver.) - 신입 프로그래머를 위한 강좌 - 인프런 | 강의

스프링 프레임워크 기본부터 실전 사용법까지! 충실하고 폭넓은 설명과 예제를 통해 현장에 바로 투입되어 활약하는 개발자로 거듭나세요., - 강의 소개 | 인프런...

www.inflearn.com

Comments