참조한 강의 : Spring & Hibernate For Beginners (www.udemy.com/course/spring-hibernate-tutorial/)
- Bean Scope
보통 다른 프로그래밍 언어에서 scope 라 하면 변수의 범위를 말하는 경우가 많다.
그러나 여기서 다룰 bean scope 는 약간 다른 의미로 쓰인다.
spring 에서의 bean scope 는 현재(2021-01-18) 기준 6개의 scope 가 있다.
1. singleton
2. prototype
3. request
4. session
5. application
6. websocket
3 ~ 6 번은 나중에 Spring MVC 부분 다룰 때, 포스팅하기로 하고,
여기선 1, 2 번만 중점적으로 다뤄본다.
(1 ~ 6 에 대한 자세한 설명은 아래 참조)
www.baeldung.com/spring-bean-scopes
- singleton scope vs prototype scope
먼저 singleton scope 는 spring 이 bean 의 인스턴스를 만들때 오로지 딱 하나만 만들고, 다른 객체들에게서 이 bean 에 대한 요청이 여러번 들어오더라도 이 bean 의 인스턴스를 참조해주는 값을 내보내는 것을 말한다.
예를들어, 앞선 포스팅 내용 중에서 TrackCoach.java 라는 파일이 있었는데, spring container 가 이 클래스를 spring bean 으로 잡아서 인스턴스를 생성한뒤, 다른 여러 객체에서 이 bean 을 요청했다고 가정해보자.
이를 그림으로 표현하면 대략 이렇게 된다.
아무리 많은 다른 객체에서 TrackCoach 에 대한 요청을 해오더라도 오로지 하나의 인스턴스 메모리만 참조하는 형태인것. (즉, call by reference 를 의미함)
이 singleton scope 는 <bean> 태그에 scope 에 대한 아무런 값을 주지 않으면 기본값으로 설정되어 있는 scope 이며, 상태정보를 다루지 않는 bean 을 다룰때 적절하다.
prototype scope 은 이와 반대로, 해당 bean 에 대한 요청이 들어올때 마다 인스턴스를 생성하는 방식이다. (call by value)
그림으로 나타내면 이런식이다.
요청할때마다 인스턴스를 만들게 되므로, 상태정보를 관리하는데에는 singleton scope 보다는 낫다.
다만 매번 인스턴스를 생성하므로 메모리를 많이 소모하게 된다.
singleton scope 와 prototype scope 에 대한 내용을 직접 코드로 작성해보자
- singleton scope code
먼저 이전 포스팅에서 사용했던 applicationContext.xml 파일을 복사하여 붙여넣기후 이름을 beanScope-applicationContext.xml 이라 짓고 코드를 아래와 같이 써준다.
- beanScope-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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="myFortuneService" class="com.luv2code.springdemo.HappyFortuneService">
</bean>
<bean id="myLoggerConfig" class="com.luv2code.springdemo.MyLoggerConfig" init-method="initLogger">
<property name="rootLoggerLevel" value="FINE" />
<property name="printedLoggerLevel" value="FINE" />
</bean>
<bean id="myCoach" class="com.luv2code.springdemo.TrackCoach">
<constructor-arg ref="myFortuneService"/>
</bean>
</beans>
|
cs |
bean 태그에 scope="singleton" 이라고 안써도 기본값이 singleton 이기 때문에 위와 같이 그대로 남겨준다
그리고 여러번의 요청이 들어와도 같은 인스턴스를 참조하는지 알아보기 위해서
BeanScopeDemoApp.java 라는 파일을 만들어준다
- BeanScopeDemoApp.java
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanScopeDemo {
public static void main(String[] args) {
// load 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);
boolean result = (theCoach == alphaCoach);
// print bean's method
System.out.println("result's value : " + result);
System.out.println("theCoach's memory address : " + theCoach);
System.out.println("alphaCoach's memory address : " + alphaCoach);
// close context
context.close();
}
}
|
cs |
위 코드에서 myCoach bean 에 대한 두번의 요청을 시도했고, 이 둘이 같은지 비교하기 위해
boolean result 를 선언했다.
그리고 이들이 서로 같은 주소값을 갖는지 보고자 각 객체를 출력하도록 해준다
이를 실행해보면
서로 동일한 메모리를 가르키고 있음을 알 수 있다.
- prototype scope code
다음은, prototype 을 코드로 짜보자
앞의 xml 파일에 scope="prototype" 만 추가해주면 된다.
- beanScope-applicationContext.xml
<bean id="myCoach" class="com.luv2code.springdemo.TrackCoach" scope="prototype">
<constructor-arg ref="myFortuneService"/>
</bean>
|
cs |
그리고 나서 다른 코드의 변경없이 BeanScopeDemoApp.java 에서 실행시켜주면
보다 싶이 서로 다른 주소값을 가짐을 알 수 있다.
- Spring Bean Life Cycle
어떤 객체의 life cycle 이란 것은 해당 객체가 언제 생성되고, 언제 죽고, 살아있는 동안 어떤 행동을 하는지 등을 표현하기 위한 개념이다.
bean life cycle 은 spring 에서 bean 이 언제 생성되고, 생존 기간동안 어떤 일들을 수행하는지, 또 언제 사라지는지 등을 표현하기 위한 개념으로 이 bean life cycle 을 그림으로 나타내면 대략 위와 같다.
(나중에 annotation 이나 다른 개념들을 배우면 사실 이것 보다 더 과정이 다양하다, 일단 뒷개념을 아직 배우지 않았으니 이것 이상은 포스팅 하지 않겠다, 더 자세한 부분은 아래 링크 참조)
www.journaldev.com/2637/spring-bean-life-cycle
처음에 spring container 가 실행된뒤, xml 에 설정한 bean 들을 인스턴스화 하고, 의존성 주입 과정을 거쳐서, bean factory 내부에서 여러 처리 작업이 일어난다. 그 후, 개발자가 init-method 를 넣어 줄 수 있고 (이 method 는 bean 이 실행되기 이전에 사용되는 method 이다), bean 들이 다 준비가 된 후, 앱이 실행되다가, 앱이 꺼질때, 가장 먼저 spring container 가 종료되면서, 개발자가 작성한 destory-method 가 실행되고, 앱이 최종적으로 종료가된다.
init-method 는 bean 이 실행되기 전,
destory-method 는 앱이 최종적으로 종료되기 전 실행된다.
두 method 는 필수 사항은 아니다.
(init-method 와 destory-method 같은 user's custom method 들은 hook 이라고 따로 부르는거 같다)
이런 류의 method 들은 DB 연결 설정하거나, 소켓을 사용한다던가, 혹은 파일처리를 할때 사용되는 method 들이다.
이런 류의 method 들의 특징은
1) 접근 제한자를 어떤 것을 사용하든 상관없다
(private, public, protected 다 가능)
2) 리턴 타입을 아무거나 해도 가능, 대부분은 void 로 설정함
3) method 이름은 아무거나 상관없다
4) 매개변수를 받을 수 없다. 그래서 매개변수 없는 메소드로 선언해야 한다.
그러면 직접 init-method 와 destory-method 를 실행해봄으로써 이들이 실제로 어떻게 실행되는지 알아보자
먼저, 앞서 사용했던 beanScope-applicationContext.xml 을 복사해서 beanLifeCycle-applicationContext.xml 이라는 파일을 만들어주고 다음과 같이 값을 바꾼다.
- beanLifeCycle-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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="myFortuneService" class="com.luv2code.springdemo.HappyFortuneService">
</bean>
<bean id="myLoggerConfig" class="com.luv2code.springdemo.MyLoggerConfig" init-method="initLogger">
<property name="rootLoggerLevel" value="FINE" />
<property name="printedLoggerLevel" value="FINE" />
</bean>
<bean id="myCoach" class="com.luv2code.springdemo.TrackCoach" init-method="doMyStartupStuff" destroy-method="doMyCleanupStuff">
<constructor-arg ref="myFortuneService"/>
</bean>
</beans>
|
cs |
<bean> 태그에 init-method 와 destory-method 가 새로운 속성값으로 들어갔다.
이 메소드들을 추가해주기 위해 TrackCoach.java 파일을 연 뒤,
아래와 같은 함수들을 추가해준다
- TrackCoach.java
public void doMyStartupStuff() {
System.out.println("doMyStartupStuff");
}
public void doMyCleanupStuff() {
System.out.println("doMyCleanupStuff");
}
|
cs |
그리고 이를 테스트 하기 위한 main 함수를 갖는 파일인
BeanLifeCycleDemoApp.java 파일을 만들어 준다
- BeanLifeCycleDemoApp.java
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanLifeCycleDemoApp {
public static void main(String[] args) {
// load 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 context
context.close();
}
}
|
cs |
그리고 실행을 해보면 다음과 같이 결과가 나옴을 볼 수 있다.
먼저, spring container 에 의해 myCoach 라는 id 값을 갖는 bean 인스턴스가 생성되고,
사용자가 정의한 init-method 가 실행되면서
doMyStartupStuff 라는 문구가 먼저 출력되었다.
그리고 나서 해당 인스턴스가 실행할 함수인 getDailyWorkout() 이 수행되었고,
마지막으로 context 가 종료되면서 destory-method 가 실행되고 스프링 앱이 최종적으로 종료되었다.
여기까지 spring bean scope 와 life cycle 에 대해서 알아보았다
다음은 annotation 에 대해서 알아본다.
- references)
1. Quick Guide to Spring Bean Scopes : www.baeldung.com/spring-bean-scopes
2. Spring Bean Life Cycle : www.journaldev.com/2637/spring-bean-life-cycle
'Spring' 카테고리의 다른 글
Spring Framework - XML 파일 없이 스프링 설정하기 (0) | 2021.01.22 |
---|---|
Spring Framework - Annotation (0) | 2021.01.20 |
Spring Framework - Dependency Injection (0) | 2021.01.18 |
Spring Framework - Inversion of Control (IoC) (0) | 2021.01.13 |
Spring Framework - Overview (0) | 2021.01.12 |