- 애노테이션 @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는 전혀 호출되지 않음