Java 관련/Spring Legecy

[Spring] DI / IoC (Bean 객체 생성_04) - Singleton

씨네 2022. 3. 13. 09:04
728x90

싱글톤 레지스트리

- 스프링이 직접 싱글톤 형태의 오브젝트를 만들고 관리하는 기능을 제공한다.

(스프링 빈 오브젝트는 내부적으로 싱글톤 레지스트리를 만들어서 연동한다.)

싱글톤 패턴으로 Bean객체를 선언하는 방법을 알아보고 간단하게 오늘 요일을 출력하는 코드를 보고자 합니다.

우선 패키지에 AbstractTest라는 이름의 추상클래스와 AbstractTest를 상속받는 각요일별 클래스를 만들었습니다. (이클립스에서 추상클래스를 먼저 만들어 놓으면 빨간줄 뜨면서 에러가 날텐데 그 에러에 마우스를 대면 자동으로 하위 클래스를 만들어줍니다)

패키지 구조

AbstractTest.java

package com.test01;

import java.util.Calendar;
import java.util.GregorianCalendar;

public abstract class AbstractTest {
	
	public abstract String dayInfo();
	
	public static AbstractTest getInstance() {
		GregorianCalendar cal = new GregorianCalendar();
		int day = cal.get(Calendar.DAY_OF_WEEK);
		
		switch(day) {
		case 1: return new Sunday();
		case 2: return new Monday();
		case 3: return new Tuesday();
		case 4: return new Wednesday();
		case 5: return new Thursday();
		case 6: return new Friday();
		case 7: return new Saturday();
		}
		
		return null;
	}

}

sunday.java

package com.test01;

public class Sunday extends AbstractTest {

	@Override
	public String dayInfo() {
		return "일요일";
	}

}

Monday.java

package com.test01;

public class Monday extends AbstractTest {

	@Override
	public String dayInfo() {
		return "월요일";
	}

}

Tuesday.java

package com.test01;

public class Tuesday extends AbstractTest {

	@Override
	public String dayInfo() {
		return "화요일";
	}

}

Wednesday.java

package com.test01;

public class Wednesday extends AbstractTest {

	@Override
	public String dayInfo() {
		return "수요일";
	}

}

Thursday.java

package com.test01;

public class Thursday extends AbstractTest {

	@Override
	public String dayInfo() {
		return "목요일";
	}

}

Friday.java

package com.test01;

public class Friday extends AbstractTest {

	@Override
	public String dayInfo() {
		return "금요일";
	}

}

Saturday.java

package com.test01;

public class Saturday extends AbstractTest {

	@Override
	public String dayInfo() {
		return "토요일";
	}

}

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="singleton" class="com.test01.AbstractTest" factory-method="getInstance"></bean>

</beans>

MTest.java

package com.test01;

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

public class MTest {

	public static void main(String[] args) {
		ApplicationContext factory = new ClassPathXmlApplicationContext("com/test01/applicationContext.xml");
		AbstractTest today = factory.getBean("singleton", AbstractTest.class);
		
		System.out.println("오늘은 " + today.dayInfo() + " 입니다.");
	}
}

실행결과

추상클래스는 객체선언을 할 수 없습니다.

따라서 AbstractTest클래스는 객체생성을 할수 없습니다.

하지만 applicationContext.xml에 보면 factory-method를 이용하여 new가 아닌 getInstance로 호출하였습니다.

해당 코드에서는 AbstractTest에 생성자가 없기때문에 factory-method="getInstance" 가 없다면 객체로 생성 할 수가 없습니다.

하지만 factory-method="getInstance"가 getInstance메서드를 찾아서 객체로 만들어줍니다.

AbstractTest의 getInstance

<bean id="singleton" class="com.test01.AbstractTest" factory-method="getInstance"></bean>
<!-- AbstractTest singleton = AbstractTest.getInstance(); -->

싱글톤은 객체가 하나만 존재하도록 선언한 것입니다.

만약 날짜를 예로 들어보면 오늘 날짜와 시간이 여러개가 존재할수 없는데 객체가 여러개 만들어져서 여러개가 생기면 난감하겠죠?

만약

AbstractTest singleton = AbstractTest.getInstance();

AbstractTest singleton02 = AbstractTest.getInstance();

두개의 객체가 있을때 해당 객체들은 singleton이기 때문에 같은 객체라고 볼수 있습니다.

사실 Calendar클래스에서는 엄격하게 보면 싱글톤패턴이라고 볼수는 없지만 이해를 돕기위해 편의상 싱글톤패턴이라고 생각하면 되겠습니다.

또 MTest에서 보면 이전과 다르게

AbstractTest today = factory.getBean("singleton", AbstractTest.class);

로 객체를 호출하였습니다.

객체를 factory메서드를 통해 넘겨 받으면 Object타입으로 넘겨 받아지기 때문에

AbstractTest today = (AbstractTest) factory.getBean("singleton");

이처럼 형변환을 해주어야 하는데 말이죠...

AbstractTest today = factory.getBean("singleton", AbstractTest.class);

이 코드는 명시적 형변환을 하지 않고 singleton 객체는 AbstractTest클래스의 타입입니다 하고 알려주는 스프링에서 만들어준 문법입니다!

사실 두가지 방법 모두 AbstractTest로 형변환을 해주는 과정입니다.

해당 코드에서 사용한 AbstractTest.class는 AbstractTest클래스의 형태로 사용하겠다 라는 의미입니다!

728x90