SpringFramework/BASIC

싱글톤타입/프로토타입 Bean객체의 범위

유혁스쿨 2020. 8. 29. 00:27
728x90
반응형

우리가 컨테이너에 Bean 객체 등록을 해놓고 컨테이너에서 필요한 객체들을 꺼내서 쓸때

똑같은 Bean 여러개를 getBean()한다면 과연 그 객체는 같은 객체를 여러개를 얻을수 있을까 하나만 얻을수있을까 에 대해서 이야기 해 봅니다.

 

객체가 만약 하나만 관리가 된다면 우리는 이것을 싱글톤이라고 부릅니다

객체가 여러개 관리가 된다프로토타입이라고 부릅니다

 

 

우리가 직접 new() 연산자를 사용하여 객체를 생성한다면 다른 어떤장치를 해놓지 않았을때 당연히 프로토타입으로 생성이 됩니다

하지만 우리가 getBean()으로 객체를 컨테이너에서 얻어온다면 어떤타입으로 나올까?

스프링 컨테이너 방식으로 객체를 얻을때, 과연 싱글톤타입으로 관리가 되는가 프로토타입으로 관리가 되는가에 대해서 알아보겠습니다.

 

Person 이라는 클래스를 만듭니다.

package com.spring.basic.ex03;

public class Person {
	private String name;
	private Integer age; 

	//게터세터생성
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
}

최근자바의흐름은 int를 싫어합니다.

 

"시대가 어느때인데 C언어 원시타입을 쓰냐~ 너네 객체지향언어 아니야? 객체로 다 표현해!"

int→Integer 이것이 요즘 추세 입니다. 자바의 흐름이 최대한 기본타입을 배제하는 추세이죠.

랩퍼형태로 표현해보겠습니다.

Person클래스의 필드 멤버변수 String타입의 name, age를 int의 객체형인 Integer로 선언합니다.

 

 

새로 prototype-config.xml 파일을 생성하고 Person클래스에 대한 Bean등록을 하겠습니다

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

	<!-- person bean에대한 빈 등록 -->
	<bean id="person" class="com.spring.basic.ex03.Person" >
   
		<property name="name" value="홍길동" />
		<property name="age" value="20" />
	
	</bean>
</beans>

필드값에대해 컨테이너 안에 객체를 미리 등록,설정합니다. setter()메서드의 이름에 맞춰서 name을 지정해주며

해당 value(초기값)값을 지정합니다.

 

 

MainClass를 만들어서 Bean을 뽑아와보겠습니다.

package com.spring.basic.ex03;

import org.springframework.context.support.GenericXmlApplicationContext;

public class MainClass {

	public static void main(String[] args) {
		GenericXmlApplicationContext ct = 
				new GenericXmlApplicationContext("classpath:prototype-config.xml");
		
        Person hong = ct.getBean("person",Person.class);
		
		//두번째 객체 생성
		Person kim = ct.getBean("person",Person.class);
		
		System.out.println("홍의 주소 : " + hong);
		System.out.println("킴의 주소 : " + kim);
		System.out.println("홍과 킴은 같은 객체인가?? : " + (hong==kim)); 
	}
}

만약 컨테이너에 등록된 person이라는 빈이 싱글톤 형태로 빈에 등록되있다면 지금 getBean()으로 얻어온 객체들은 결국 몇개일까요? 결과는 하나입니다.

그렇다면 두개의 주소는 같을까요 다를까요?

정답은 같겠죠?

 

 

 

hong과 kim은 같은객체

두 객체는 같은 Hash값을 가지고있습니다.

스프링컨테이너에 bean을 등록하게되면 자동으로 싱글톤 클래스형태로 등록이 됩니다

우리가 만약 웹프로그래밍을 할 때 싱글톤형식이 필요한 클래스들은 따로 설정 할 필요가 없다는것 입니다 DAO같은 클래스를 만들 때 말이죠.

등록된 bean같은경우에는 객체를 여러개 만들 필요성이 없다는것이죠.

만들어진 객체를 재활용 해서 쓰도록 메모리 상에서 설정을 해놓은것입니다

그러나 때로는 싱글톤이 아닌 형태의 클래스를 구성해야할 때가 있습니다. 그것을 어떻게 하는지 해보자

우선 디폴트가 싱글톤인 이유는 싱글톤 사용예시가 훨씬 많습니다.

스프링에서는 객체를 싱글톤으로 구현해야할때가 많기때문에 디폴트가 싱글톤으로 설정이 되어 있습니다..

package com.spring.basic.ex03;

import org.springframework.context.support.GenericXmlApplicationContext;

public class MainClass {

	public static void main(String[] args) {
		GenericXmlApplicationContext ct = 
				new GenericXmlApplicationContext("classpath:prototype-config.xml");
		
        Person hong = ct.getBean("person",Person.class);
		
		//두번째 객체 생성
		Person kim = ct.getBean("person",Person.class);
		
		System.out.println("홍의 주소 : " + hong);
		System.out.println("킴의 주소 : " + kim);
		System.out.println("홍과 킴은 같은 객체인가?? : " + (hong==kim)); 
        System.out.println("======================추가코드===================");
		kim.setName("김철수");
		kim.setAge(30);
		System.out.println("홍의이름 : " +hong.getName());
		System.out.println("홍의나이 : "+ hong.getAge());

		System.out.println("킴의이름 : " +kim.getName());
		System.out.println("킴의나이 : "+ kim.getAge());
	}
}

두번째로 만든 Person객체 reference인 kim을통해서 setName()을 김철수로 바꾸고 setAge()를 30으로 바꿉니다.

 

 

 

우린 분명히 kim이라는 변수 데이터를 통해서 데이터를 제어했습니다.

하지만 hong객체의 이름이 김철수, 나이가 30으로 각각 변경이 되었습니다

결국에 kim과 hong은 같은객체이므로 우리가 kim으로 제어를해도 hong의 getter()메서드들이 제어됩니다.

kim과 똑같은 하나의 객체를 바라보고 있기 때문에 싱글톤이기 때문에 이런문제가 발생합니다.

 

만약에 우리가 빈을 등록할 때 "나 싱글톤으로 구현할것이 아닌데요? Person의 객체를 갯빈할때마다 새로 만들면 안될까여?" 이렇게 하려고 한다면 xml설정파일의 등록된 bean에 scope태그를 줍니다.

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

	<!-- person bean에대한 빈 등록 -->
	<bean id="person" class="com.spring.basic.ex03.Person" scope="prototype" >
   
		<property name="name" value="홍길동" />
		<property name="age" value="20" />
	
	</bean>
</beans>

scope="prototype" 라는 옵션을 줍니다.

scope의 디폴트는 scope="singleton"으로 지정되있습니다. 보통 자바에서 default설정은 생략되게 됩니다.

prototype으로 우리가 변경을 가한다면 그 객체에서만 변경이될것입니다.

 

 

 

 

 

잘 변경되시나요?

두 객체의 주소가 달라지고 같은객체가 아니라고 하면서 hong의 이름과 나이에는 변동이없고 kim의 이름과 나이에만 setter()코드가 작동하게됩니다.

 

우리가 "prototype-config.xml 설정파일에서 scope를 prototype으로 변경할 수 있다",

"기본은 싱글톤이다 왜냐하면 스프링에서는 싱글톤을 가장 많이 사용하기 때문이다." 요 정도로 이해하시면 되겠습니다.

사실 프로토타입 같은 경우엔 우리가 별다른 클래스에서 내부설정을 하지 않으면 일반적으로 프로토타입으로 설정이됩니다 .

싱글톤은 우리가 싱글톤을 구현하기위한 코드를 써줘야합니다. 생성자를 private으로 제한한다거나 하는등의

그런코드 없이도 스프링에서는 빈을 등록 할 때 쉽게 싱글톤을 구현할수 있도록 디폴트가 싱글톤으로 잡혀져있습니다

 

 

 


+자동 의존성 주입 설정이 되어있는 LegacyProject에서 ProtoType으로 설정하는법.

 

 

 

만약 LegacyProject에서 servlet-context.xml파일에

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">


	<!-- 어노테이션을 활용하여 자동으로 빈 등록을 하게 해주는 설정태그 -->
	<context:component-scan base-package="빈등록을 할 클래스들의 패키지 경로" />
	
	
	
</beans:beans>

 빈 등록과 의존성 주입이 자동으로 설정되어있다면 이때도 default기본설정으로 singleTone방식이 설정되어있습니다.

 

자동으로 설정되있는것이 확인되었다면 프로토타입으로 변경하고 싶은 객체의 클래스를 찾아가

@Scope 어노테이션을 선언하고

@Scope("prototype")

인자값으로 "prototype"을 속성값으로 줍니다.

@Service
@Scope("prototype")
public class ServiceImpl implements Service{

	@Autowired
    private Dao dao;
        
}

 

굳이 DAO에는 prototype으로 설정하는것이 좋은방법은 아닙니다.

어차피 클래스의 필드를 공유하고있기 때문에 객체를 굳이 여러개 생성할 필요가 없다는것 입니다.

더 비효율적 입니다.

728x90
반응형