[Spring] Bean 생명주기 콜백

GWANSU SHIN·2022년 7월 25일
0

spring

목록 보기
7/7

Spring Bean의 Life Cycle

객체 생성 -> 의존관계 주입

Spring Bean의 Event Life Cycle

Spring Container 생성 -> Spring Bean 생성 -> 의존관계 주입 -> 초기화 콜백 사용 -> 소멸전 콜백 -> 스프링 종료

  • 초기화 콜백 : Bean이 생성되고, Bean의 의존관계 주입이 완료된 후 호출
  • 소멸 전 콜백 : Bean이 소멸되기 직전에 호출

Spring Bean 생명주기 콜백

  • 객체의 초기화와 소멸(종료) 작업

기본 코드: NetworkClient.java

package hello.core.lifecycle;

public class NetworkClient {
	private String url;
    
	public NetworkClient() {
		System.out.println("생성자 호출, url = " + url);
		connect();
		call("초기화 연결 메시지");
	}
    
	public void setUrl(String url) {
		this.url = url;
	}
    
	//서비스 시작시 호출
	public void connect() {
		System.out.println("connect: " + url);
	}
    
	public void call(String message) {
		System.out.println("call: " + url + " message = " + message);
	}
    
	//서비스 종료시 호출
	public void disconnect() {
		System.out.println("close: " + url);
	}
}

기본 코드: BeanLifeCycleTest.java

package hello.core.lifecycle;

import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

public class BeanLifeCycleTest {
	@Test
	public void lifeCycleTest() {
		ConfigurableApplicationContext ac = new AnnotationConfigApplicationContext(LifeCycleConfig.class);
		NetworkClient client = ac.getBean(NetworkClient.class);
		ac.close(); //스프링 컨테이너를 종료, ConfigurableApplicationContext 필요
 }
 
 	@Configuration
	 static class LifeCycleConfig {
	 	@Bean
		public NetworkClient networkClient() {
	 		NetworkClient networkClient = new NetworkClient();
			networkClient.setUrl("http://hello-spring.dev");
			return networkClient;
		}
    }
}

1. 인터페이스 InitializingBean, DisposableBean

NetworkClient.java

import org.springframework.beans.factory.InitializingBean;

public class NetworkClient implements InitializingBean, DisposableBean {
	private String url;
    
	public NetworkClient() {
		System.out.println("생성자 호출, url = " + url);
	}
    
	public void setUrl(String url) {
		this.url = url;
	}
    
	//서비스 시작시 호출
	public void connect() {
		System.out.println("connect: " + url);
	}
    
	public void call(String message) {
		System.out.println("call: " + url + " message = " + message);
	}
    
	//서비스 종료시 호출
 	public void disConnect() {
		System.out.println("close + " + url);
 	}
    
 	@Override
 	public void afterPropertiesSet() throws Exception {
 		connect();
 		call("초기화 연결 메시지");
 	}
    
 	@Override
 	public void destroy() throws Exception {
 		disConnect();
 	}
}
  • InitializingBean : afterPropertiesSet() 메소드로 초기화 지원
  • DisposableBean : destroy() 메소드로 소멸을 지원
  • 초기화, 소멸 메소드의 이름을 변경할 수 없음
  • 코드 수정이 불가능한 외부 라이브러리에 적용할 수 없음
  • 따라서 거의 사용되지 않음

2. 설정 정보(AppConfig)에 빈 등록 초기화, 소멸 메서드 지정

NetworkClient.java

package hello.core.lifecycle;

public class NetworkClient {
	private String url;
	
    public NetworkClient() {
 		Sytem.out.println("생성자 호출, url = " + url);
 	}
    
 	public void setUrl(String url) {
 		this.url = url;
 	}
    
 	//서비스 시작시 호출
 	public void connect() {
 		System.out.println("connect: " + url);
 	}
    
 	public void call(String message) {
 		System.out.println("call: " + url + " message = " + message);
 	}
    
 	//서비스 종료시 호출
 	public void disConnect() {
 		System.out.println("close + " + url);
 	}
    
 	public void init() {
 		System.out.println("NetworkClient.init");
 		connect();
 		call("초기화 연결 메시지");
 	}
    
 	public void close() {
 		System.out.println("NetworkClient.close");
 		disConnect();
 	}
}

BeanLifeCycleTest.java

@Configuration
static class LifeCycleConfig {
	@Bean(initMethod = "init", destroyMethod = "close")
	public NetworkClient networkClient() {
		NetworkClient networkClient = new NetworkClient();
		networkClient.setUrl("http://hello-spring.dev");
		return networkClient;
	}
}
  • 메소드 이름을 직접 지정할 수 있음
  • 코드가 아니라 설정 정보를 사용하기 때문에 코드를 고칠 수 없는 외부 라이브러리에도 초기화, 종료 메서드를 적용할 수 있음

3. @PostConstruct, @PreDestroy

NetworkClient.java

package hello.core.lifecycle;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class NetworkClient {
	private String url;
    
	public NetworkClient() {
		System.out.println("생성자 호출, url = " + url);
 	}
    
	public void setUrl(String url) {
 		this.url = url;
	}
    
 //서비스 시작시 호출
 	public void connect() {
		System.out.println("connect: " + url);
	}
    
 	public void call(String message) {
		System.out.println("call: " + url + " message = " + message);
	}
    
 	//서비스 종료시 호출
	public void disConnect() {
		System.out.println("close + " + url);
	}
    
	@PostConstruct
	public void init() {
		System.out.println("NetworkClient.init");
		connect();
		call("초기화 연결 메시지");
	}
    
	@PreDestroy
	public void close() {
		System.out.println("NetworkClient.close");
		disConnect();
	}
}

BeanLifeCycleTest.java

@Configuration
static class LifeCycleConfig {
	@Bean
	public NetworkClient networkClient() {
		NetworkClient networkClient = new NetworkClient();
		networkClient.setUrl("http://hello-spring.dev");
		return networkClient;
	}
}
  • 최신 Spring에서 가장 권장하는 방법
  • Spring이 아닌 Java 표준(패키지: javax.annotation.PostConstruct)
  • 외부 라이브러리에는 적용할 수 없음

결론

@PostConstruct, @PreDestroy을 주로 사용하자
코드를 고칠 수 없는 외부 라이브러리를 초기화, 종료해야 하면 @BeaninitMethod , destroyMethod 메소드를 사용하자

Reference

[인프런] 스프링 핵심 원리 - 기본편

0개의 댓글