Dev/Springboot

스프링 빈 라이프 사이클 ( Spring Bean Life Cycle ) - Bean Scope, Bean Profile, Bean 초기화

린네의 2024. 5. 16. 10:19

 

해당 게시글은 사실 DI 나 IoC작성시 관련해서 함께 작성하려고 했는데 어쩌다 보니 작성 순서가 뒤로 밀렸다.  이 글을 읽고나면 아래 순서대로 한번씩 읽어보는 것을 추천한다 :)

 

( 사실 이번 글을 작성하다가 세션 종료로 글이 통째로 한번 날아가서 마음이 아픈 상태다 ^_ㅠ..)

 

 

2024.05.06 - [개발/springboot] - Spring의 DI - 코드를 유연하고 단순하게 하는 방법

 

Spring의 DI - 코드를 유연하고 단순하게 하는 방법

이전 AOP에 이어 Spring POJO의 또 다른 키워드인 DI와 IoC에 대한 개념을 함께 정리해볼까 한다.AOP에 대한 게시글이 궁금하다면 아래 링크를 참조 바란다. 2024.05.06 - [개발/springboot] - Spring의 AOP - 공통

zigo-autumn.tistory.com

 

2024.05.06 - [개발/springboot] - Spring 의 AOP - 공통 소스 파일을 분리하여 관리할 수 있는 방법

 

Spring 의 AOP - 공통 소스 파일을 분리하여 관리할 수 있는 방법

java OOP 관련 게시글을 작성하다가 Spring POJO 에서 필수적으로 알아야 하는 AOP/IoC/DI/PSA에 대해 정리한 글을 공유하면 좋을 것 같아 글을 남겨 본다.  그중에서도 이번 게시글은 AOP에 관련된 내용

zigo-autumn.tistory.com

 

2024.05.16 - [개발/springboot] - AOP 심화 ( feat. Life Cycle of Bean ) - @Advice 예제

 

AOP 심화 ( feat. Life Cycle of Bean ) - @Advice 예제

이전 게시글에서 AOP에 대해 간단하게 정리했는데 실제 예제등에 대해 부족한점이 있는 것 같아 내용을 보충하고자 해당 게시글을 작성하게 되었다.  2024.05.06 - [개발/springboot] - Spring 의 AOP - 공

zigo-autumn.tistory.com

 

 

Bean의 라이프 사이클

 

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

 

따라서 다음과 같은 라이프 사이클을 가진다.

스프링 컨테이너 생성 ( 어플리케이션 실행 ) 

1. 빈 생성 

2. 빈 주입 및 초기화  :  콜백 메서드 실행
3. 빈 사용 
4. 빈 소멸 : 콜백 메서드 실행 

스프링 컨테이너 종료 

 

여기서 콜백 메서드란, 특정 조건이 만족되면 시스템 내부에서 자동으로 호출되도록 설계된 메서드를 의미한다.

 

 

[출처] https://hyperskill.org/learn/step/19550

 

 

 

 

또한 이런 빈은 Singleton Bean과 Prototype Bean 으로 나눌수 있는데 그 차이는 다음과 같다.

 

 

  • Singleton Bean 

 

[출처] https://liltdevs.tistory.com/116

 

 

 

Singleton Bean은 '스프링 컨테이너 생성 -> 스프링 빈 생성 -> 의존관계 주입 -> 초기화 콜백 -> 사용 -> 소멸 전 콜백 -> 스프링 종료' 순으로 수행된다.  

 

위 그림에서 @PostContruct가 초기화 콜백에 해당한다. 반대로 @PreDestory를 사용하면 소멸 전 콜백되어야 할 내용을 명시할 수 잇다.

 

 

  • Prototype Bean

 

[출처] https://liltdevs.tistory.com/116

 

 

Prototype Bean은 '스프링 컨테이너 생성 -> 스프링 빈 생성 -> 의존 관계 주입 -> 초기화 콜백 -> 사용 -> GC 수거'순으로 수행 된다. 

 

Spring에서는 기본적으로 모든 Bean을 singleton으로 생성하고 관리한다.

 

여기서 공통적으로 나오는 빈 생명 콜백 메서드 설정방법은 총 세가지로 나뉜다.

 

  • @PostConstruct /  @PreDestroy 
@Component
public class TestBean {
	//...
	@PostConstruct 
    public void init() {
        System.out.println("빈 초기화");
        start();
    }
    
	@PreDestroy
    public void close() {
        System.out.println("빈 소멸 직전");
        finish();
    }
}

 

스프링에서 권장하는 방법으로 소멸 전 콜백 메서드에 추가해서 사용할 수 있다. Spring에 종속적인 기술이아니라 Java 표준이다. 따라서 스프링이 아닌 다인 컨테이너에서도 사용 가능하다.  단, 외부 라이브러리에 대한 초기화 및 종료 설정에는 사용할 수 없다.

 

@PostConstruct를 사용하면 초기화를 수행하여 객체의 값을 설정할 수 있으며, @PreDestroy를 사용하여 ApplicationContext에서 Bean을 제거할 수 있다.

 

@PostConstruct 가 java9 이상부터 deperected 되었지만, deprecated 된 라이브러리는 java.xml.ws.annotation 이지

jakarta.annotation이 아니기 때문에 java17 에서 실제 사용시에 문제는 없었다. 단 java9와 java11 에서는  javax.annotation-api 종속성의 추가가 필요하니 주의가 필요해보인다.

 

 

  • Bean 옵션에 초기화/종료 메서드를 지정

@Bean 의 추가 설정으로 메서드명을 명시하는 방식으로 초기화 및 종료 전 콜백 메서드를 등록할 수 있다. 클래스 내부 코드가 아닌 설정하는 곳에서 지정하기 때문에 내부 코드를 고칠 수 없는 경우에 유용하다.

 

@Configuration
class TestLifeCycleConfig {

    @Bean(initMethod = "init", destroyMethod = "close") //메서드 이름
    public TestBean testBean() {
        return new TestBean();
    }
}

 

이 때 destroyMethod 에는 추론(inferred)이라는 기능이 있다. 라이브러리들 대부분이 종료 메서드를 호출할 때 close, shutdown을 사용하는것을 이용하여 destroydMethod에서는 inferred를 close, shutdown이라는 이름의 메서드를 자동으로 호출해 준다. 

 

기본 값이므로 destroyMethod를 따로 설정하지 않아도 지정되며 추론을 사용하고 싶지 않다면 destroyMethod="" 과 같이 빈 공백을 지정해줘야 한다.

 

 

  • InitializingBean, DisposableBean 인터페이스

해당 방법은 스프링 라이브러리에 직접적으로 의존하는 과거에 사용되던 기술이다.

InitailizingBean, DisposableBean 을 implements 하여 사용할 수 있으나 권장되지 않으므로 예제는 생략했다.

 

 

 

Bean - Scope

스프링은 기본적으로 빈(Bean)이라는 개념으로 자바 객체를 만들고 싱글톤화 시켜 관리한다. 이 객체들은 스프링의 IoC 컨테이너에 의해 생성되고 소멸되며 관리되는데, 이 때 Bean이 관리되는 범위를 Bean Scope라고 표현한다.

 

Scope 설명
Singleton 하나의 Bean 정의에 대해서 Spring IoC Container 내에 단 하나의 객체만 존재 함
Prototype 하나의 Bean 정의에 대해서 다수의 객체가 존재할 수 있음
request 하나의 Bean 정의에 대해서 하나의 HTTP request의 생명주기 안에 단 하나의 객체만 존재함. 즉, 각각의 HTTP request는 자신만의 객체를 가짐.  Web-aware Spring ApplicationContext 안에서만 유효함

웹 요청이 들어오고 나갈 때 까지 유지되는 Scope
session 하나의 Bean 정의에 대해서 하나의 HTTP Session 생명주기 안에 단 하나의 객체만 존재한다. Web-aware Spring ApplicationContext 안에서만 유효하다.

웹 세션이 생성되고 종료될 때까지 유지되는 Scope
global session 하나의 Bean 정의에 대해서 하나의 global HTTP Session의 생명주기 안에 단 하나의 객체만 존재한다. 일반적으로 portlet context안에서 유효하다.  Web-awre Spring ApplicationContext 안에서만 유효하다. 

웹의 서블릿 컨텍스트와 같은 범위로 유지되는 Scope

 

여기서 request, session, global session 은 함께 웹 관련 스코프로 분류 된다. 이런 웹 관련 스코프는 일반 spring 어플리케이션이 아닌 SpringMVC Web Application에서만 사용 된다. 

이런 Web Scope를 통해  실무에서 request를 통해 하나의 요청에 대해 로그들을 한번에 저장해서 관리할 수 있다.

 

아래는 @Scope를 이용해서 Http request 요청별로 로그를 저장하기 위한 @Component 예제이다.

@Component  
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)  
@RequiredArgsConstructor  
public class LogScope {
… 

}

 

 

 

계속 강조하지만, Spring의 기본 Scope 정책은 Sigleton 이다.  따라서 Bean을 조회하면 컨테이너가 존재할 때 항상 같은 인스턴스의 빈을 반환하며, 컨테이너 생성 시점에 함께 생성되고 초기화 된다.

 

 

 

Bean - Profile

 동일한 타입의 Bean이 여러개 생성되어 있다. 하지만 환경별로 이 Bean이 다르게 동작하게 하고 싶다면 어떻게 해야할까? 

이럴 때 사용할 수 있는 것이 바로 @Profile 이다.

 

@Configuration 을 클래스별로 나눠서 작성하거나 @Profile 조건이 다른 동일한 이름의 Bean을 선언하고 메서드 이름을 다르게 해서 사용할 수 있다.

 

 

 

번외 -  Bean ApplicationContext

ApplicationContext는 스프링 프레임워크의 가장 대표적인 객체로 BeanFactory를 상속받아서 구현된 객체이다. BeanFactory를 상속 받는것 뿐만 아니라, 다른 여러 스프링 인터페이스를 상속받아서 구현되어 있어 Bean을 조회하고 관리하는 기능뿐만 아니라 확장 기능을 제공한다.

 

  • BeanFactory : Bean을 생성하고 연결하는 등의 기본 기능을 정의한다. 부모 역할에 해당한다
  • ApplicationContext : BeanFactory를 확장해서 여러 기능을 추가한다. 자식 역할에 해당한다.

쉽게 말하면 Application Context 는 객체(Bean)을 저장하는 저장소의 역할을 한다.

 

@Configuration, @Component 를 통해 클래스들을 Application Context 에 Bean이라는 개념으로 저장할 수 있는 것이다.

''