본문 바로가기

Spring

스프링 빈 라이프 사이클(Spring Bean Life Cycle)

728x90
반응형

스프링 빈은 스프링컨테이너에 의해서 관리된다.

프로그램이 실행되면서 스프링 컨테이너가 시작되고, 컨테이너의 요청에 따라 빈의 인스턴스를 생성하고 의존성을 주입한다.

스프링 컨테이너가 닫히면 빈이 파괴된다.

init(), destroy() 메소드 대신 사용자 정의 메소드 이름을 선택할 수 있다.

빈이 인스턴스화될 때 init메소드를 실행하고 컨테이너를 닫을 때 destroy()메소드를 실행한다.


빈 라이프 사이클

빈 객체 생성

     ⬇️ 

빈 프로퍼티 설정 

     ⬇️ 

BeanNameAware.setBeanName()

     ⬇️ 

ApplicationContextAware.setApplicationContect()

     ⬇️ 

BeanPostProcessor 초기화 전처리

postProcessBeforeInitialization

     ⬇️ 

초기화

@PostCunstruct

InitializingBean.afterPropertiesSet()

Custom init method

     ⬇️ 

BeanPostProcessor 초기화 후처리

postProcessAfterInitialization

     ⬇️ 

빈 객체 사용

     ⬇️ 

소멸

@PreDestroy메서드

DisposableBean.destroy()

Cusom destroy 메서드


BeanNameAware

BeanFactory에서 빈이름을 알고 싶을 때 구현하는 인터페이스.

객체가 빈 이름에 의존하는 것은 권장되지 않는 방법이다.

일반적으로 취약하고 불필요한 의존성이다.

void setBeanName(String name)

스프링 컨테이너에 설정된 Bean ID를 나타낸다.

Bean ID가 없으면 name이 들어온다.

InitializingBean.afterPropertiesSet()이 사용자 정의 초기화 메서드 실행 전에 호출된다. 

public class MyBeanName implements BeanNameAware {

    @Override
    public void setBeanName(String beanName) {
        System.out.println(beanName);
    }
}
@Configuration
public class Config {

    @Bean(name = "myCustomBeanName")
    public MyBeanName getMyBeanName() {
        return new MyBeanName();
    }
}

Bean을 스프링 컨테이너에 등록한다.

MyBeanName 클래스에 @Bean(name="myCustomBeanName")을 이용해서 명시적으로 이름을 할당한다.

 

AnnotationConfigApplicationContext context 
  = new AnnotationConfigApplicationContext(Config.class);

MyBeanName myBeanName = context.getBean(MyBeanName.class);

setBeanName은 "myCustomBeanName"을 출력한다.

 


ApplicationContextAware

실행되는 ApplicationContext에 대한 알림을 받고자할 때 구현하는 인터페이스 

public interface ApplicationContextAware {

    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class ApplicationContextAwareTest implements ApplicationContextAware {
	ApplicationContext context;
	public ApplicationContext getContext() {
		return context;
	}
	@Override
	public void setApplicationContext(ApplicationContext context)
			throws BeansException {
		this.context=context;
	}
}
<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="testA" class="com.concretepage.A"/>
    <bean id="appcontext" class="com.concretepage.ApplicationContextAwareTest"/>
</beans>
public class A {
	public void doTask(){
		System.out.println("Do some task.");
	}
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringTest {
	public static void main(String[] args) {
		AbstractApplicationContext  context = new ClassPathXmlApplicationContext("app-conf.xml");
		ApplicationContextAwareTest appcontext= (ApplicationContextAwareTest)context.getBean("appcontext");
		ApplicationContext appCon =appcontext.getContext();
		A a= (A)appCon.getBean("testA");
		a.doTask();
		context.registerShutdownHook();
	}
}

 


BeanPostProcessor

Bean 인스턴스의 사용자 정의 수정을 허용하는 Factory Hook. 

@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException

 

postProcessBeforeInitialization

InitializingBean의 afterPropertiesSet 또는 사용자 정의 init-method 초기화 콜백 전에 실행된다. 

 

postProcessAfterinitialization

Bean초기화 콜백 후에 실행되는 method. 반환되는 Bean Instance는 래핑된 객체일 수 있다. 

public class HelloWorld {
   private String message;

   public void setMessage(String message){
      this.message  = message;
   }
   public void getMessage(){
      System.out.println("Your Message : " + message);
   }
   public void init(){
      System.out.println("Bean is going through init.");
   }
   public void destroy(){
      System.out.println("Bean will destroy now.");
   }
}

 

import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.BeansException;

public class InitHelloWorld implements BeanPostProcessor {
   public Object postProcessBeforeInitialization(Object bean, String beanName) 
      throws BeansException {
      
      System.out.println("BeforeInitialization : " + beanName);
      return bean;  // you can return any other object as well
   }
   public Object postProcessAfterInitialization(Object bean, String beanName) 
      throws BeansException {
      
      System.out.println("AfterInitialization : " + beanName);
      return bean;  // you can return any other object as well
   }
}
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   public static void main(String[] args) {
      AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");

      HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
      obj.getMessage();
      context.registerShutdownHook();
   }
}
<?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-3.0.xsd">

   <bean id = "helloWorld" class = "com.tutorialspoint.HelloWorld"
      init-method = "init" destroy-method = "destroy">
      <property name = "message" value = "Hello World!"/>
   </bean>

   <bean class = "com.tutorialspoint.InitHelloWorld" />

</beans>

OUTPUT

더보기
BeforeInitialization : helloWorld
Bean is going through init.
AfterInitialization : helloWorld
Your Message : Hello World!
Bean will destroy now.

 


@PostConstruct

의존성 주입이 끝난 후 초기화를 수행하기 위해 실행하는 메서드. 클래스가 서비스되기 전에 호출되어야 한다.

이 어노테이션은 종속성 주입을 지원하는 모든 클래스에 지원되어야 한다. 

 

java9부터는 Deprecated되었다.


afterPropertiesSet()

InitializingBean 인터페이스의 메소드. 

BeanFactory에 의해 모든 Property가 설정되고 난 뒤 실행되는 메소드.

실행시점의 custom초기화로직이 필요하거나 주입받은 property를 확인하는 용도.


@PreDestroy

마지막 소멸단계로 스프링컨테이너에서 빈을 제거하기 전에 할 작업이 있을 때 사용한다.


DisposableBean

스프링 프레임워크에서 제공하는 인터페이스로 스프링프레잌워크에 의존적이다.

Bean이 소멸되기 전에 실행된다.


사용자등록에 의한 빈은 빈 생명주기 콜백 메서드를 호출할 수 있는데 
1. 인터페이스(InitializingBean, DisposableBean)
2. 설정 정보에 초기화 method, 종료 method 지정
3. @PostConstruct, @PreDestory 어노테이션 사용
모두 사용하지 않을 경우 빈을 인스턴스하는 시점에 초기화 되고 스프링IoC컨테이너가 종료되는 시점에 소멸된다.

 

Reference
https://www.baeldung.com/spring-bean-name-factory-aware
https://www.concretepage.com/spring/example_applicationcontextaware_spring
https://www.tutorialspoint.com/spring/spring_bean_post_processors.htm

 

 

728x90
반응형