티스토리 뷰

1. Spring Bean Scope

  Scope란 무엇인가? Scope는 bean의 life cycle을 부르는 것이다.

얼마나 bean이 존재하고, 얼마나 많은 인스턴스가 생성되고, spring 환경에서 어떻게 bean이 공유되는가 에 관한것이다.

Spring에서의  bean의 default scope값은 singleton이다.

1) Singleton Scope

  Spring container가 default값으로 오직 하나의 bean의 인스턴스를 만든다. 

그 bean은 메모리에서 캐쉬에 저장되어 있다.

bean에 대한 모든 request에 공유된 reference를 반환할 것이다. 같은 bean에.

그래서 결국 오직 하나의 bean이 있고 그것을 모두가 공유하는 것이다.

서로 다른 app에서 같은 bean을 호출 하면, 같은 메모리를 가리키게 된다. 

하나를 공유하게 되는것이다. 

singleton을 사용하기에 가장 좋은 bean은 어떠한 state도 유지할 필요 없는 stateless bean이다.

 

Additional Spring Bean Scope

Bean Scope에는 위와 같은 종류의 Scope가 있지만, request, session, global-session같은 경우 웹과 관련되어 있기 때문에 나중에 다시 다룰 것이다.

singleton과 상반되는 bean scope가 바로 prototype scope이다.

 

2) Prototyte Scope

  Prototype Scope는 singleton scope와 다르게 각각의 request마다 새로운 객체가 생성된다

따라서 stateful data의 추적하는데 사용하게 좋다.

 

3) Singleton과 Prototype 비교 예시

 <bean id="myFortuneService"
    	class="com.luv2code.springdemo.HappyFortuneService">
   
    </bean>
    <bean id="myCoach" 
    class="com.luv2code.springdemo.WeightLiftingCoach"
    scope="prototype">
    
    	<!-- set up constructor injection -->
    	<constructor-arg ref="myFortuneService"/>
    </bean>
package com.luv2code.springdemo;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanScopeDemoApp {

	public static void main(String[] args) {
		
		//load the spring configuration file
		ClassPathXmlApplicationContext context = 
				new ClassPathXmlApplicationContext("beanScope-applicationContext.xml");
		
		// retrieve bean from spring container
		Coach theCoach = context.getBean("myCoach",Coach.class);
		Coach alphaCoach = context.getBean("myCoach",Coach.class);
		
		//check if they are the same
		boolean result = (theCoach == alphaCoach);

		//print out the results
		System.out.println("\nPointing to the same object : " + result);
		
		System.out.println("\nMemory location for theCoach : " + theCoach);
		System.out.println("\nMemory location for alphaCoach : " + alphaCoach + "\n");
		
		//close the context
		context.close();
	}
}

 

위 beanScope-applicationContext.xml에서 scope를 prototype으로 설정하거나, default값인 singleton으로 설정해 출력 값을 비교해 본다면, BeanScopeDemoApp에서의 theCoach 인스턴스와 alphaCoach 인스턴스가 가리키는 메모리 주소가 scope를 prototype로 설정 했을 경우, 달라지며 같은 bean을 공유하는 것이 아닌 서로 다른 bean을 각각 생성해서 사용하는 것을 알 수 있다.

 

*stateful & stateless란

stateful application은 명확한 user의 detail들을 기억한다. 예를어, 프로필, 취향, 유저 액션과 같은 것들이다.

이런 정보는 시스템의 지위와 관련이 있다.

클라우드에 있는 어떤 웹사이트를 사용하는 쇼핑카트를 예로 들 수 있다.

매번 물건을 선택해서 카트에 담고, 이전에 담은 물건에 추가해서 물건을 담는다. 그리고 체크아웃 페이지에서 결제를 한다. 

반면 stateless application은 이전의 작동이나 작업에 대한 어떠한 참조 정보도 저장하지 않는 것을 말한다.

매번 처음부터 작업을 진행하고 매 short-term request를 위해 프린트, CDN 이나 웹서버 같은 기능을 제공한다.

예를들면, 누군가 search engine에서 검색어를 입력하고 enter 버튼을 눌렀다. 이 경우 만약 검색 기능이 방해 받거나 다른 이유로 인해 닫혀진다면, 이전 request에 대한 저장된 데이터가 없기 때문에 다시 처음부터 새로 시작해야 한다. 

( 이러한 이유에서 장바구니 경우 client가 다른경우, 같은 request를 보내더라도 서로 다르게 작동 해야 하기 때문에 prototype Scope이 적절해 보이고, 검색어의 enter버튼과 같이 어떤 기능을 구현하는 객체 경우는 서로 다른 request에 각기 다르게 반응할 필요가 없기에, singleton Scope 사용이 적절해 보인다.)

 

2. Bean LifeCycle methods

1) Bean의 LifeCycle

Bean의 lifecycle이란, spring container가 시작하면, 

① beans are instantiated

②dependencies are injected

③ internal spring process

그리고 나면 bean을 app에서 회수하기 전, ④ custom initialization code를 추가 할 수 있는 옵션이 생긴다.

여기서 bean이 사용할 준비가 된다. 그래서 method를 부를 수도 있고, bean으로 작업을 할 수 있는것이다.

그리고 나서 bean이 app의 context.close(); 와 같이 어느 시점에서 container가 닫히면, 

⑤ custom destroy method를 부를 수도 있다. 

이 코드는 actual application이 멈추기 전이나 실제적인 bean lifecycle이 끝나기 전에 실행될 것이다.

 

여기서 중요한 것이 ④, ⑤번인데, bean initialization 동안에 custom code를 추가 할 수 있고,

bean destruction 동안에 custom code를 추가 할 수 있다.

(이것을 hook이라 부른다.) 이는 xml 파일, 즉 config file에 configuration entry를 만들어 줌으로서 가능해진다.

2) Development Process

1. define your methods for init and destroy
2. configure the method names in spring config file.

 

3) Bean LifeCycle methods 예시 (initialization & destruction)

  TrackCoach class에 다음과 같이 method를 추가한다. (method이름에는 어떠한 규정이나 관습이 없으므로 짓고싶은대로 지으면 된다)

	//add an init method (custom hook)
	public void doMyStartupStuff() {
		System.out.println("TrackCoach : inside method doMyStartupStuff");
	}
	//add a destroy method
	public void doMyCleanupStuffYoYo() {
		System.out.println("TrackCoach : inside method doMyCleanupStuffYoYo");
	}

Config file에서 다음과 같이 해당 메소드를 추가 해준다.

<bean id="myFortuneService"
    	class="com.luv2code.springdemo.HappyFortuneService">
   
    </bean>
    <bean id="myCoach" 
    class="com.luv2code.springdemo.TrackCoach"
    init-method="doMyStartupStuff"
    destroy-method="doMyCleanupStuffYoYo">
    	<!-- set up constructor injection -->
    	<constructor-arg ref="myFortuneService"/>
    </bean>

App에서 실행한다.

package com.luv2code.springdemo;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanLifeCycleDemoApp {
	public static void main(String[] args) {
		
		//load the spring configuration file
		ClassPathXmlApplicationContext context = 
				new ClassPathXmlApplicationContext("beanLifeCycle-applicationContext.xml");
	
		// retrieve bean from spring container
		Coach theCoach = context.getBean("myCoach",Coach.class);
		
		System.out.println(theCoach.getDailyWorkout());
		
		//close the context
		context.close();
	}
}

그러면 결과로  myCoach가 생성되자마자 init-method가 실행되는것을 볼 수 있고,

context.close();로 bean의 destruction이 일어난 후 destroy-method가 실행되는 것을 볼 수 있다.

 

4) Init and Destroy Method Signatures

Access modifier

method는 어떠한 접근제어자(Access Modifier)를 가질 수 있다. (public, private protected)

Return Type

init, destroy method는 return type을 가질 수 있지만, void가 가장 일반적으로 쓰인다.

return type을 주더라도 return value를 return받을 수가 없다.(위 코드를 보면)

따라서 결과적으로 void가 가장 일반적으로 쓰인다.

Method name

어떠한 method 이름을 가져도 상관없다.

Arguments

method는 어떠한 인수, 매개변수를 가질 수 없다. method는 no-arg 여야만 한다.

 

* argument와 parameter의 차이점 

종종 parameter(매개변수)와 argument(전달인자)를 적당히 섞어서 쓰이기도 하지만 엄밀히 말해서 

parameter(매개변수)는 함수의 정의 부분에 나열되어 있는 변수들을 의미하며

argument(전달인자)는 함수를 호출할 때 전달되는 실제 값을 의미한다.

예시) f(x) = x^2에서 x는 parameter, f(2)에서의 2는 argument.

developer.mozilla.org/en-US/docs/Glossary/Parameter를 참고 하면 될듯.

* Prototype scoped bean에서, Spring은 destroy method를 부르지 않는다.

이것은 xml configuration 뿐만 아니라 annotation-based configuration에서도 같이 적용되는데,

다른 scope들과는 다르게, Spring은 prototype bean의 완전한 lifecycle을 운영하지 않는다.

-> custom coding으로 prototype bean의 destroy method를 생성할 수 있지만 custom coding을 해줘야 한다. (직접 만들어 줘야 한다.)

여기서는 다루지 않겠다...

최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday