본문 바로가기

Programming/Spring

Spring - Bean 초기화 및 생명주기

BeanFactory & ApplicationContext

bean factory - 스프링의 IoC 담당하는 핵심 컨테이너

빈을 등록/생성/조회/반환/관리한다. 보통은 bean factory 바로 사용하지 않고 이를 확장한 application context 이용한다. BeanFactory bean factory 구현하는 interface 이다. (getBean()등의 메소드가 정의되어 있음)

application context - bean factory 확장한 IoC 컨테이너

빈의 등록/생성/조회/반환/관리의 기능은 bean factory 같지만, 여기에 spring 각종 부가 서비스를 추가로 제공한다. ApplicationContext application context 구현해야 하는 interface이여, BeanFactory 상속한다

 


ApplicationContext가 추가적으로 지원하는 기능
1. MessageSource를 지원하여 애플리케이션에서 필요한 메시지들을 관리하는 것이 가능
2. Spring 프레임워크에서 관리하는 POJO 빈들 중 ApplicationListener를 구현하여 설정파일에 등록할 경우 등록된 리스너에게 이벤트를 전달하는 것이 가능

즉, ApplicationContext를 이용할 경우 애플리케이션내에 간단한 이벤트 기능을 구현하는 것이 가능

3. 애플리케이션내에서는 파일, URL과 같은 다양한 자원(Resource)에 접근할 필요가 있다.

ResourceLoader를 지원함으로 다양한 하위레벨의 자원을 Spring 프레임워크의 Resource 인스턴스로 생성하는 것이 가능

※ ApplicationContext를 직접 사용하는 방법을 알아둘 경우 테스트 프로그램을 작성할 때 유용하게 사용할 수 있다.

 

 

Spring 프레임워크에서 빈의 생명주기

 

POJO 초기화 과정
1. Spring 프레임워크는 먼저 빈 설정파일의 POJO 빈을 인스턴스화하지 않은 상태로 빈 설정 파일 정보를 초기화한다.

   빈 설정파일의 정보를 초기화하면서 XML DTD에 대하여 유효한지를 체크한다.
2. 빈 인스턴스를 생성하면서 의존관계에 있는 빈이 존재하는지의 여부를 체크하여 의존 관계에 있는 빈이 존재하지

   않는다면 빈의 초기화가 실패한다.
3. 의존관계에 있는 빈의 체크가 완료되면 setter 메써드를 호출하거나(Setter Injection의 경우), 생성자의 인자

   (Constructor Injection의 경우)로 실질적인 값을 추가하거나 다른 빈에 대한 레퍼런스(reference)를 전달한다.
4. 생성한 빈이 BeanNameAware 인스턴스이면 setBeanName() 메소드를 호출한다.
5. 생성한 빈이 BeanFactoryAware 인스턴스이면 setBeanFactory() 메소드를 호출한다.
6. 생성한 빈이 ApplicationContextAware 인스턴스이면 setApplicationContext() 메소드를 호출한다.

   이 과정은 ApplicationContext를 이용하여 초기할 때만 실행된다.
7. 생성한 빈이 InitializingBean 인스턴스이면 afterProperties() 메소드를 호출한다.
8. 생성한 빈의 설정파일에 init-method가 설정되어 있다면 init-method에 해당하는 메소드를 호출한다

 

종료 메소드를 호출하는 과정
1. 생성한 빈이 DisposableBean 인스턴스이면 destory() 메소드를 호출한다.
2. 생성한 빈의 설정파일에 destroy-method가 설정되어 있다면 destroy-method에 해당하는 메소드를 호출한다. 

POJO 빈에서 빈 설정 정보에 접근하기
POJO 빈에서 BeanNameAware, BeanFactoryAware, ApplicationContextAware 인터페이스 중 필요한 인터페이스를 상속하고 인터페이스의 메소드를 구현하면 된다.

 

빈의 생명주기 제어하기
Spring IoC 컨테이너의 Bean 초기화 및 소멸 작업의 커스트마이징을 하고싶을때 Spring의 초기화 콜백 메서드와 소멸 콜백 메서드를 인식하게하여 사용하면 되는데 그 방법으로는 아래 3가지 방법이 있다.

 
1. InitializingBean 과 DisposableBean 생명주기 인터페이스를 구현하고 초기화와 소멸작업을 위한

   afterPropertiesSet()destroy() 메소드를 구현.

2. Bean선언시(xml) init-methoddestroy-method 속성을 설정해 콜백 메소드의 이름을 지정한다.
3. Spring 2.5이후부터는 JSR-250(Common Annotations for the Java Plaform)에 정의되어 있는  

   @PostConstruct@PreDestroy 생명주기 어노테이션을 사용하여 초기화 및 소멸 콜백 메서드를 적용할

   수 있다. 이 콜백 메소드를 호출하기 위해서는 IoC컨테이너에 CommonAnnotationBeanPostProcessor

   인스턴스가 등록돼 있어야한다.

 


빈 생명주기 제어의 간단한 예제
- Cashier Class는 장바구니의 Product들을 계산하는데 사용되며, 계산할 때마다 시각과 수량을 텍스트 파일에 기록한다. 이때 파일을 기록하기전 파일객체를 초기화 하고, 파일 작성후 소멸(close)시킨다.

 

Cashier Class

package com.apress.springrecipes.shop;


import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Date;

public class Cashier{
private String name;
private String path;
private BufferedWriter writer;

public void setBeanName(String beanName) {
this.name = beanName;
}

public String getPath() {
return path;
}

public void setPath(String path) {
this.path = path;
}

public void openFile() throws IOException {
File logFile = new File(path, name + ".txt");
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(logFile, true)));
}

public void checkout(ShoppingCart cart) throws IOException {
double total = 0;
for (Product product : cart.getItems()) { total += product.getPrice(); }
writer.write(new Date() + "\t" + total + "\r\n");
writer.flush();
}

public void closeFile() throws IOException {
writer.close();
}
}

 

Bean Config

<beans ...>

...

<bean id=cashier1" class="com.apress.springrecipes.shop.Cashier">

<property name="name" value="casher1" />

<property name="name" value="casher1" />

</bean>

</beans>

 

 

1. InitializingBean과 DisposableBean 인터페이스 구현

...

import org.springframework.beans.factory.InitializingBean;

import org.springframework.beans.factory.DisposableBean;


public class Cashier implements InitializingBean, DisposableBean{

...

public void afterPropertiesSet() throws Exception {

openFile();

}

 

public void destroy() throws Exception {

closeFile();

}

}

 

위와 같이 스프링에 종속된 인터페이스를 구현하면 빈이 스프링에 종속되므로 스프링 IoC 컨테이너 외부에서 재사용하지 못한다.

 

 

2. init-method와 destroy-method 속성 설정

<bean id="cashier1" class="com.apress.springrecipes.shop.Cashier" init-method="openFile" destroy-method="closeFile">

<property name="name" value="cashier1" />

<property name="path" value="c:/cashier" />

</bean>

 

 

3. @PostConstruct와 @PreDestroy 어노테이션 적용

package com.apress.springrecipes.shop;

...

import javax.annotation.PostConstruct;

import javax.annotation.PreDestroy;


public class Cashier {

...

@PostConstruct

public void openFile() throws IOException {

File logFile = new File(path, name + ".txt");

writer = new BufferedWriter(new OutputStreamWriter(

new FileOutputStream(logFile, true)));

}

...

@PreDestroy

public void closeFile() throws IOException {

writer.close();

}

}

그리고 CommonAnnotationBeanPostProcessor 인스턴스를 IoC 컨테이너에 추가하면 된다.

 

<beans ...>

<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />

<bean id="cashier1" class="com.apress.springrecipes.shop.Cashier">

<property name="name" value="cashier1" />

<property name="path" value="c:/cashier" />

</bean>

</beans>

 

 

 

참조 :  http://www.javajigi.net/pages/viewpage.action?pageId=2621452, http://ultteky.egloos.com/10795411

'Programming > Spring' 카테고리의 다른 글

Spring - Transaction1 (스프링의 트랜잭션 지원)  (0) 2012.12.06
Spring - POJO  (2) 2012.05.14
Spring - Bean Scope  (0) 2012.05.10
Spring - IoC & DI  (0) 2012.05.09
Spring - AOP 개념 정리  (6) 2012.05.08