
데이터베이스 커넥션 풀이나 네트워크 소켓처럼 애플리케이션 시작 시점에 미리 연결을 해두고, 애플리케이션 종료 시점에 연결을 모두 종료하는 작업을 진행하려면, 객체의 초기화와 종료 작업이 필요하다.
package hello.core.lifecycle;
public class NetworkClient {
private String url;
public NetworkClient() {
System.out.println("생성자 호출, url = " + url);
// 생성과 동시에 연결
connect();
// 초기화 메세지 출력
call("초기화 연결 메세지");
}
// 생성과 동시에 호출 됨
// 서비스 시작 시 호출
public void connect() {
System.out.println("connect : " + url);
}
public void setUrl(String url) {
this.url = url;
}
// 생성과 동시에 초기화 메세지 출력
public void call(String msg){
System.out.println("call = " + url + " msg = " + msg);
}
// 서비스 종료 시 호출
public void disconnect(){
System.out.println("close = " + url);
}
}
package hello.core.lifecycle;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
public class BeanLifeCycleTest {
@Test
@DisplayName("빈 라이프사이클")
public void lifeCycleTest(){
ConfigurableApplicationContext ac = new AnnotationConfigApplicationContext(LifeCycleConfig.class);
NetworkClient bean = ac.getBean(NetworkClient.class);
ac.close();
}
@Configuration
static class LifeCycleConfig{
@Bean
public NetworkClient networkClient(){
// 인스턴스 생성
NetworkClient networkClient = new NetworkClient();
// 수정자 주입으로 url 삽입
networkClient.setUrl("http://hello-spring.dev");
// networkClient.call("안녕하세요");
return networkClient;
}
}
}

networkClient가@Bean으로 등록되면서 생성자 호출이 완료되고 그 후에 수정자 주입으로 url이 삽입된다. 따라서null값이 나오고connect()또한null이 된다.
@Configuration
static class LifeCycleConfig{
@Bean
public NetworkClient networkClient(){
NetworkClient networkClient = new NetworkClient();
networkClient.setUrl("http://hello-spring.dev");
networkClient.call("안녕하세요");
return networkClient;
}
}
✨위와 같이 의존관계 주입이 완료된 후 객체를 호출하게 되면 아래와 같이 정상적으로 호출된다.
초기화 콜백 : 빈이 생성되고, 빈의 의존관계 주입이 완료된 후 호출
소멸전 콜백 : 빈이 소멸되기 직전에 호출
💡 객체의 생성과 초기화를 분리하는 것이 좋다
생성자는 필수 정보(파라미터)를 받고, 메모리를 할당해서 객체를 생성해주는 책임을 갖는다. 초기화는 생성된 객체를 바탕으로 외부 커넥션을 연결하는 등 무거운 동작을 한다. 따라서 생성자 안에서 무거운 초기화 작업을 하는 것 보다 생성하는 부분과 초기화 하는 부분을 나누는 것이 유지보수 관점에서 좋다.
✅ 1. 인터페이스(IntializingBean, DisposableBean)
✅ 2. 설정 정보에 초기화 메서드, 종료 메서드 지정
✅ 3. @PostConstruct,@PreDestory 애너테이션 지원
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 connect() {
System.out.println("connect : " + url);
}
public void setUrl(String url) {
this.url = url;
}
public void call(String msg){
System.out.println("call = " + url + " msg = " + msg);
}
// 서비스 종료 시 호출
public void disconnect(){
System.out.println("close = " + url);
}
// DisposableBean 오버라이딩
// 소멸
@Override
public void destroy() throws Exception {
disconnect();
}
// InitializingBean 오버라이딩
// 초기화
@Override
public void afterPropertiesSet() throws Exception {
connect();
call("초기화 연결 메세지");
}
}

package hello.core.lifecycle;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class NetworkClient{
private String url;
public NetworkClient() {
System.out.println("생성자 호출, url = " + url);
}
// 서비스 시작 시 호출
public void connect() {
System.out.println("connect : " + url);
}
public void setUrl(String url) {
this.url = url;
}
public void call(String msg){
System.out.println("call = " + url + " msg = " + msg);
}
// 서비스 종료 시 호출
public void disconnect(){
System.out.println("close = " + url);
}
// 소멸
public void close() {
disconnect();
}
// 연결 후
public void init(){
connect();
call("초기화 연결 메세지");
}
}
package hello.core.lifecycle;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
public class BeanLifeCycleTest {
@Test
@DisplayName("빈 라이프사이클")
public void lifeCycleTest(){
ConfigurableApplicationContext ac = new AnnotationConfigApplicationContext(LifeCycleConfig.class);
NetworkClient bean = ac.getBean(NetworkClient.class);
ac.close();
}
@Configuration
static class LifeCycleConfig{
@Bean(initMethod = "init", destroyMethod = "close")
public NetworkClient networkClient(){
NetworkClient networkClient = new NetworkClient();
networkClient.setUrl("http://hello-spring.dev");
return networkClient;
}
}
}

@Bean의destroyMethod속성에는 기본 값이(inferred)(추론)으로 등록되어 있어서 clse, shutdown이라는 이름의 메서드를 자동으로 호출해준다. 따라서 종료 메서드는 따로 적어주지 않아도 잘 동작하게된다.
@PostConstruct,@PreDestory 애너테이션 지원package hello.core.lifecycle;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class NetworkClient{
private String url;
public NetworkClient() {
System.out.println("생성자 호출, url = " + url);
}
// 서비스 시작 시 호출
public void connect() {
System.out.println("connect : " + url);
}
public void setUrl(String url) {
this.url = url;
}
public void call(String msg){
System.out.println("call = " + url + " msg = " + msg);
}
// 서비스 종료 시 호출
public void disconnect(){
System.out.println("close = " + url);
}
// 소멸
@PreDestroy
public void close() {
disconnect();
}
// 초기화
@PostConstruct
public void init(){
connect();
call("초기화 연결 메세지");
}
}
package hello.core.lifecycle;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
public class BeanLifeCycleTest {
@Test
@DisplayName("빈 라이프사이클")
public void lifeCycleTest(){
ConfigurableApplicationContext ac = new AnnotationConfigApplicationContext(LifeCycleConfig.class);
NetworkClient bean = ac.getBean(NetworkClient.class);
ac.close();
}
@Configuration
static class LifeCycleConfig{
@Bean
public NetworkClient networkClient(){
NetworkClient networkClient = new NetworkClient();
networkClient.setUrl("http://hello-spring.dev");
return networkClient;
}
}
}

@PostConstruct @PreDestory 애너테이션 특징import jakarta.annotation.PostConstruct; 이다. 자바 표준이므로 스프링이 아닌 다른 컨테이너에서도 동작한다.