Spring Boot 빈 라이프사이클과 범위
빈의 라이프사이클과 Scope 범위 알아보기
  • Spring

컨테이너 라이프 사이클

image

위의 간단한 예제를 통해 알아보도록 하겠습니다.

image

AnnotationConfigApplicationContext를 통해 컨테이너 초기화가 됩니다.
컨테이너가 초기화가 완료되면 사용가능한 상태가 되고

image

getBean을 통해 bean을 가져다 사용할 수 있습니다.

image

Bean의 사용이 끝나면 close를 통해 컨테이너의 소멸처리가 됩니다.

이러한 컨테이너의 초기화 -> 사용 -> 종료 가 일어날 때 bean은 어떤 라이프라이클 과정을 거치게 될까요?

Bean 라이프 사이클

컨테이너가 초기화될 때 bean의 라이프사이클도 시작됩니다.

image

  1. 컨테이너가 초기화될 때 등록된 @Bean을 검색합니다.
  2. 검색된 @Bean이 등록되고 bean의 객체가 생성됩니다.
  3. @Beand에서 필요한 의존 설정이 이루어지고
  4. *Aware인터페이스가 순차적으로 호출됩니다.

aware인터페이스는 본래 spring내부에서 사용하기 위해 만들어졌지만, bean이 컨테이너의 정보 (id, name 등)에 접근하기 위해서는 필요한 Aware를 상속받아 원하는 기능을 구현할 수 있습니다.

다만 ApplicationContextAware를 상속받아 처리하면 Spring에 의존이 강하게 생기므로 가능하면 지양해야 합니다.

  1. *Aware 의 인터페이스가 순차적으로 호출이 끝나면 초기화 과정이 일어납니다.

어노테이션 -> 인터페이스 상속 -> @Bean 선언 의 순으로 초기화 메서드가 실행됩니다.
선언하지 않았거나 상속받지 않았을 경우 당연히 호출되지 않습니다.

여기까지 진행되면 Bean은 사용가능한 상태가 됩니다.
즉, 컨테이너의 getBean을 통해 불려와지고 정상 사용이 가능합니다.

모든 사용이 끝나고 컨테이너가 close를 통해 소멸될 때
Bean역시 소멸의 라이프 라이클을 가지게 됩니다.

  1. 초기화때와 동일하게 어노테이션 -> 인터페이스 상속 -> @Bean 선언 의 순서로 소멸 함수가 실행됩니다.

초기화와 소멸 과정에서 호출되는 메서드들에 대해 좀 더 자세히 살펴보겠습니다.

Bean의 생성/소멸 시 메서드 실행하기

Bean 생성과 소멸시 호출되는 메서드

Bean이 생성되고 소멸될 때 필요한 함수를 실행하기 위해서는 상속 또는 메서드를 지정해주면 필요한 처리를 할 수 있습니다.

이렇게 생셩/소멸 시 처리해야할 작업으로는 db connection을 관리한다던가, 채팅의 경우 socket 연결/종료 등의 작업을 할 수 있습니다.

@어노테이션 (@PostConstruct, @PreDestory)

먼저 어노테이션을 이용해 생성/소멸이 필요한 처리를 할 수 있습니다.

image

Service 클래스 안에서 생성시, 소멸시 실행 될 함수에
@PostConstruct를 통해 생성시 실행할 메서드
@PreDestory를 통해 소멸시 실행할 메서드를
지정할 수 있습니다.

이렇게 지정하고 실행해보면 위 캡쳐와 같이 init -> 함수 실행 -> destory 가 순차적으로 실행되는것을 확인할 수 있습니다.

어노테이션으로 지정하는 방식은 java 9버전부터 deprecated된 기능이고, java 11에서부터는 제거된 기능입니다.

지금 사용하려고 하면 찾을 수 없는 어노테이션이라는 오류를 볼 수 있을것입니다!

인터페이스 상속을 통핸 처리

image

InitializingBeanDesposableBean을 상속받아 처리하는 방법이 있습니다.
위 인터페이스 선언을 보면
InitializingBeanaterPropertiseSet을 호출하고
DesposableBeandestory를 호출하는것을 볼 수 있습니다.

image

두 개의 인터페이스를 상속받아 aterPropertiseSet, destory 함수를 override하여 재정의한 후 필요한 처리를 할 수 있습니다.

인터페이스를 상속받아 처리하는 방법은 spring에 의존성이 생기기 때문에 추천하지는 않는 방법입니다.

@Bean선언 시 실행할 메서드 지정

@Bean 선언 시 초기화, 소멸 시 실행할 함수를 지정하는것도 가능합니다.

@Bean(initMethod = "foo", destoryMethod = "bar") 와 같은 방법으로 지정이 가능하며, 꼭 쌍으로 둘 다 지정해줘야하는것은 아니며 필요한 것만 지정하는것도 가능합니다.

예를들어 @Bean(initMethod = "foo") 와 같이 사용하는것도 문제없습니다.

image

생성/소멸 시 실행 할 함수를 우선 생성해두고 (initdestory)

image

@Bean 선언시 호출 할 함수를 지정해주고 프로그램을 실행해보면
역시 순서대로 잘 호출되는것을 볼 수 있습니다.

이렇게 @Bean에 호출할 함수를 지정하는 방식은 프로젝트 내에 코드를 가지고있지 않은경우. 예를들어 외부 라이브러리를 가져다 사용했을 경우 외부 라이브러리의 초기화, 소멸을 여기서 호출해줄 수 있습니다.

Bean Scope 범위

Bean을 선언할 때 Scope의 범위를 지정하지 않으면 default로는 singleton으로 생성됩니다. 즉 getBean을 호출할 때마다 새로운 인스턴스를 생성하는것이 아니라 싱글톤으로 리턴되도록 Spring에서 관리해줍니다.

이는 개발자의 Scope의 선언을 통해 범위를 지정해줄 수 있습니다.

Scope 설명
singleton 기본(Default) 싱글톤 스코프. 하나의 Bean 정의에 대해서 Container 내에 단 하나의 객체만 존재
prototype 어플리케이션에서 요청시 (getBean()) 마다 스프링이 새 인스턴스를 생성
request HTTP 요청별로 인스턴스화 되며 요청이 끝나면 소멸
session HTTP 세션별로 인스턴스화되며 세션이 끝나며 소멸
global session 하나의 Bean 정의에 대해서 전역적인 HTTP session의 라이프사이클이 되는 범위

사용하는 방법은

@Bean
@Scope("prototype")

와 같이 사용할 수 있습니다.
prototype으로 선언할 경우 위 설명처럼 getBean을 호출할 때마다 새로운 인스턴스가 생성되고 주의해야할점은 리소스 해제에 대해 개발자가 직접 처리해줘야 합니다.

위 Bean의 라이프사이클에서 소멸과정 (destory)가 Scope를 prototype으로 지정하면 호출되지 않습니다.

이는 개발자에게 소멸에 대한 처리를 구현할 책임을 주고 있습니다.