티스토리 뷰

김영한 - 스프링 핵심 원리 기본편을 듣고 정리한 내용입니다.

 

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard

 

스프링 핵심 원리 - 기본편 - 인프런 | 강의

스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., - 강의 소개 | 인프런...

www.inflearn.com

📝목차

8. 빈 생명주기 콜백

  • 빈 생명주기 콜백 시작
  • 인터페이스 InitializingBean, DisposableBean
  • 빈 등록 초기화, 소멸 메서드 지정
  • 애노테이션 @PostConstruct, @PreDestory

📌빈 생명주기 콜백 시작

예제코드, 테스트 하위에 생성

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);
 	}
}

스프링 환경설정과 실행

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;
 		}
 	}
}

결과

생성자 호출, url = null
connect: null
call: null message = 초기화 연결 메시지

스프링빈 라이프 사이클

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

스프링은 의존관계 주입이 완료되면 스프링 빈에게 콜백 메서드를 통해서 초기화 시점을 알려주는 다양한 기능 제공

 

스프링 빈의 이벤트 라이프사이클

스프링 컨테이너 생성 -> 스프링 빈 생성 -> 의존관계 주입 -> 초기화 콜백 -> 사용 -> 소멸전 콜백 -> 스프링 종료

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

💡빈 생명주기 콜백 3가지 방법 (스프링)

  • 인터페이스(InitializingBean, DisposableBean)
  • 설정 정보에 초기화 메서드, 종료 메서드 지정
  • @PostConstruct, @PreDestroy 애노테이션 지원

📌인터페이스 InitializingBean, DisposableBean

package hello.core.lifecycle;
import org.springframework.beans.factory.DisposableBean;
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() 메서드로 소멸을 지원한다.

출력 결과

생성자 호출, url = null
NetworkClient.afterPropertiesSet
connect: http://hello-spring.dev
call: http://hello-spring.dev message = 초기화 연결 메시지
13:24:49.043 [main] DEBUG
org.springframework.context.annotation.AnnotationConfigApplicationContext -
Closing NetworkClient.destroy
close + http://hello-spring.dev
  • 스프링 컨테이너의 종료가 호출되자 소멸 메소드가 호출 됨

💡초기화, 소멸 인터페이스 단점

  • 스프링 전용 인터페이스
  • 초기화, 소멸 메서드의 이름을 변경할 수 없다.

📌빈 등록 초기화, 소멸 메서드 지정

설정 정보를 사용하도록 변경

package hello.core.lifecycle;
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);
 	}
 	public void init() {
 		System.out.println("NetworkClient.init");
 		connect();
 		call("초기화 연결 메시지");
 	}
 	public void close() {
 		System.out.println("NetworkClient.close");
 		disConnect();
 	}
}

설정 정보에 초기화 소멸 메서드 지정

@Configuration
static class LifeCycleConfig {

 	@Bean(initMethod = "init", destroyMethod = "close")
 	public NetworkClient networkClient() {
 		NetworkClient networkClient = new NetworkClient();
 		networkClient.setUrl("http://hello-spring.dev");
 		return networkClient;
 	}
}

결과

생성자 호출, url = null
NetworkClient.init
connect: http://hello-spring.dev
call: http://hello-spring.dev message = 초기화 연결 메시지
13:33:10.029 [main] DEBUG
org.springframework.context.annotation.AnnotationConfigApplicationContext -
Closing NetworkClient.close
close + http://hello-spring.dev

설정 정보 사용 특징

  • 메서드 이름을 자유롭게 줄 수 있다.
  • 스프링 빈이 스프링 코드에 의존하지 않는다.
  • 코드가 아니라 설정 정보를 사용하기 때문에 코드를 고칠 수 없는 외부 라이브러리에도 초기화, 종료 메서드를 적용할 수 있다.

종료 메서드 추론

  • 라이브러리는 대부분 close, shutdown 종료 메서드 사용
  • @Bean의 destroyMethod는 기본값이 inferred (추론) 으로 동록되어 있다.
  • 추론 기능을 사용하기 싫으면 destroyMethod="" 처럼 빈 공백을 지정하면 된다.

📌애노테이션 @PostConstruct, @PreDestory

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();
 	}
}
@Configuration
static class LifeCycleConfig {

 	@Bean
 	public NetworkClient networkClient() {
 		NetworkClient networkClient = new NetworkClient();
 		networkClient.setUrl("http://hello-spring.dev");
 		return networkClient;
 	}
}

실행 결과

생성자 호출, url = null
NetworkClient.init
connect: http://hello-spring.dev
call: http://hello-spring.dev message = 초기화 연결 메시지
19:40:50.269 [main] DEBUG
org.springframework.context.annotation.AnnotationConfigApplicationContext -
Closing NetworkClient.close
close + http://hello-spring.dev
  • @PostConstruct, @PreDestroy: 초기화와 종료를 실행할 수 있다.

💡@PostConstruct, @PreDestroy 애노테이션 특징

  • 최신 스프링에서 권장하는 방법
  • 패키지를 잘 보면 javax.annotation.PostConstruct 이다. 스프링에 종속적인 기술이 아니라 JSR-250 라는 자바 표준이다. 따라서 스프링이 아닌 다른 컨테이너에서도 동작한다.
  • 유일한 단점은 외부 라이브러리에는 적용하지 못한다는 것이다. 외부 라이브러리를 초기화, 종료 해야 하면 @Bean의 기능을 사용하자.

  정리

  • @PostConstruct, @PreDestroy 애노테이션 사용하자
  • 코드를 고칠 수 없는 외부 라이브러리를 초기화, 종료해야 하면 @Bean 의 initMethod , destroyMethod 를 사용하자.