본문 바로가기
Learning-log/Spring & JPA

(스프링 핵심 원리 - 기본편) 8-(4)애노테이션 @PostConstruct, 9-(1) 빈 스코프란?, (2) 프로토타입 스코프

by why제곱 2023. 4. 12.

- 애노테이션 @PostConstruct

  • 이 방법 쓰면 된다!
  • 이 애노테이션의 패키지는 javax => java에서 공식적으로 지원하는 패키지(스프링에 종속적인 기술이 아니라 JSR-250이라는 자바 표준. ) 따라서 혹시 다른 컨테이너를 쓰더라도 그대로 사용 가능
  • 간편함. 최신 스프링에서 권장하는 방법
  • 컴포넌트 스캔과 잘 어울림
  • 단점 : 외부 라이브러리에는 적용 불가. 외부 라이브러리를 초기화, 종료해야 하면 @Bean 기능을 사용하자.

 

- 빈 스코프란?

  • 스프링 빈 : 스프링 컨테이너 시작과 함께 생성, 스프링 컨테이너 종료될 때까지 유지됐다고 배웠음.
  • 이는 스프링 빈이 기본적으로 싱글톤 스코프로 생성되기 때문. 
  • 싱글톤 : 기본 스코프, 스프링 컨테이너의 시작과 종료까지 유지되는 가장 넓은 범위의 스코프
  • 프로토타입 : 스프링 컨테이너는 프로토타입 빈의 생성과 의존관계 주입까지만 관여. 더는 관리하지 않는 매우 짧은 범위의 스코프 => 종료 메서드 호출이 안 됨. 
  • 웹 관련 스코프
    • "request" : 웹 요청이 들어오고 나갈 때까지 유지되는 스코프 / 스프링 웹과 관련한 기능이 들어가야 사용 가능. 웹의 요청이 들어와서 쭉 돌고 고객의 요청이 나갈 때 (response) 종료
    • "session" : 웹 세션이 생성되고 종료될 때까지 유지되는 스코프 
    • "application" : 웹의 서블릿 컨텍스와 같은 범위로 유지되는 스코프

 

 

- 프로토타입 스코프

  • 싱글톤의 경우, 빈을 조회하면 항상 같은 인스턴스의 스플이 빈을 반환
  • 반면 프로토타입 스코프를 스프링 컨테이너에 조회하면 스프링 컨테이너는 항상 새로운 인스턴스 생성해서 반환
  • 프로토타입 빈 요청 
    • 클라이언트의 prototypeBean요청 -> 요청 들어올 때마다 새로운 빈 생성 (의존관계 필요하면 주입) =>  해당 prototypeBean이 여러개 생성됨.
    • 그렇게 생성된 빈을 클라이언트에 반환
    • 이후에 스프링 컨테이너에 같은 요청이 오면 항상 새로운 프로토 타입 빈을 생성해서 반환
  • 핵심은 스프링 컨테이너는 프로토타입 빈을 생성하고 의존관계 주입, 초기화까지만 처리. 이후 생성된 프로토타입 빈을 관리하지 않음. 프로토타입 빈을 관리할 책임은 프로토타입 빈을 받은 클라이언트에 있다. 그래서 @PreDestroy 같은 종료 메서드가 호출되지 않음. 이는 프로토타입 빈을 호출한 클라이언트가 직접 종료해줘야 함.
  • 코드로 테스트해보기
package hello.core.scope;

import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Scope;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import static org.assertj.core.api.Assertions.assertThat;

public class PrototypeTest {


    @Test
    void prototypeBeanFind(){
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(PrototypeBean.class);

        System.out.println("find prototypeBean1");
        PrototypeBean prototypeBean1 = ac.getBean(PrototypeBean.class);
        System.out.println("find prototypeBean1");
        PrototypeBean prototypeBean2 = ac.getBean(PrototypeBean.class);
        System.out.println("find prototypeBean1" + prototypeBean1);
        System.out.println("find prototypeBean1"+ prototypeBean2);
        assertThat(prototypeBean1).isNotSameAs(prototypeBean2);
    }

    @Scope("prototype")
    static class PrototypeBean{
        @PostConstruct
        public void init(){
            System.out.println("PrototypeBean.init");
        }

        @PreDestroy
        public void destroy(){
            System.out.println("PrototypeBean.destroy");
        }
    }

}

 

  • 결과
    • 두 인스턴스도 다른 인스턴스임을 확인할 수 있음.
    • destroy는 전혀 호출되지 않음