[Spring] 빈 스코프

Ho·2022년 7월 25일
0

Spring

목록 보기
8/8

빈 스코프

빈이 생성되고 존재할 수 있는 범위를 뜻한다.

스프링 빈의 스코프 종류

  • singleton : 기본 스코프, 스프링 컨테이너의 시작부터 종료까지 유지되는 가장 넓은 범위의 스코프
  • prototype : 스프링 컨테이너는 prototype 빈의 생성과 의존관계 주입까지만 관여하고 더는 관리하지 않는 짧은 범위의 스코프
  • 웹 관련 스코프
    • request : 웹 요청이 들어오고 나갈때 까지 유지되는 스코프
    • session : 웹 세션이 생성되고 종료될 때 까지 유지되는 스코프
    • application : 웹의 서블릿 컨텍스트와 같은 범위로 유지되는 스코프

빈 스코프 지정 방법

자동 등록

@Scope("prototype")
@Component
public class HelloBean {}

수동 등록

@Scope("prototype")
@Bean
PrototypeBean HelloBean() {
    return new HelloBean();
}

싱글톤 빈 스코프

  • 싱글톤 빈은 스프링 컨테이너 시작시에 빈을 한번만 생성하고 스프링 컨테이너 종료시 까지 유지한다.
  • 스프링 빈 요청시 초기에 생성하여 관리하고 있는 스프링 빈을 반환한다.
  • 여러번의 요청이 와도 같은 객체 인스턴스의 스프링 빈을 반환한다.

프로토타입 빈 스코프


프로토타입 스코프 빈은 스프링 컨테이너에 빈을 요청하는 시점에 생성되고 의존관계가 주입된다.

의존관계 주입 이후 프로토타입 빈을 반환한다.
이후에 같은 요청이 오면 항상 새로운 프로토타입 빈을 생성하여 반환한다.

정리

스프링 컨테이너는 프로토타입 빈을 생성하고 의존관계주입, 초기화까지만 처리한다. 빈을 반환한 이후에는 프로토타입 빈을 관리하지 않는다.
@PreDestroy와 같은 종료 메서드는 호출되지 않으므로 종료 시에 처리해야하는 부분은 빈을 반환받은 클라이언트에 책임이 있다.


싱글톤과 프로토타입

싱글톤 빈이 프로토타입 빈을 주입받는 경우
ClientBean은 싱글톤 PrototypeBean은 프로토타입이라고 가정하고 아래 코드를 보면

static class ClientBean {
    private final PrototypeBean prototypeBean;
    
    @Autowired
    public ClientBean(PrototypeBean prototypeBean) {
        this.prototypeBean = prototypeBean;
    }
    
    public int logic() {
        prototypeBean.addCount();
        int count = prototypeBean.getCount();
        return count;
    } 
}
  • ClientBean이 스프링 빈으로 등록되면서 의존관계를 주입받기 때문에 PrototypeBean도 스프링 빈으로 등록되고 ClientBean에 주입되어야한다.
  • 스프링 컨테이너는 의존관계 주입 이후 PrototypeBean을 더이상 관리하지 않는다.
  • ClientBean은 싱글톤이므로 스프링 컨테이너가 관리한다.

이러한 경우 ClientBean을 요청하는 다른 서비스들은 이미 ClientBean에 주입된 PrototypeBean을 사용하게 되고 이는 프로토타입 스코프의 빈을 싱글톤 스코프 빈 처럼 사용하게 된다.


Provider

DL(dependency LookUp) : 의존관계를 외부에서 주입(DI) 받는 것이 아니라 직접 필요한 의존관계를 찾는 것을 말한다.

스프링 빈에서 DL을 하기 위하여 스프링의 ApplicationContext 전체를 주입 받는 것은 스프링 컨테이너에 종속적인 코드가 되고, 단위테스트도 어려워진다.
이러한 경우 DL의 기능을 제공하는 Provider를 사용하면 된다.

ObjectProvider

지정한 빈을 컨테이너에서 대신 찾아주는 DL을 제공하는 것이 ObjectProvider이다.

static class ClientBean {

    @Autowired
    private ObjectProvider<PrototypeBean> prototypeBeanProvider;

    public int logic() {
        PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
        prototypeBean.addCount();
        int count = prototypeBean.getCount();
        return count;
    }
}
  • 싱글톤 빈에서 ObjectProvider를 주입받는다.
  • ObjectProvidergetObject()로 원하는 타입의 스프링 빈을 가져온다.(DL)
  • 이때 프로토타입의 빈을 요청하면 스프링 컨테이너는 요청마다 새로운 프로토타입 빈을 생성하여 반환한다.

JSR-330 Provider

자바 표준을 사용하는 방법으로 javax.inject.Provider를 사용할 수 있다.
build.gradle에서 dependencies에
implementation 'javax.inject:javax.inject:1' 를 추가하면 된다.

javax.inject.Provider

package javax.inject;
    public interface Provider<T> {
    T get(); 
}

Provider는 get() 메소드를 제공한다.

static class ClientBean {

    @Autowired
    private Provider<PrototypeBean> prototypeBeanProvider;

    public int logic() {
        PrototypeBean prototypeBean = prototypeBeanProvider.get();
        prototypeBean.addCount();
        int count = prototypeBean.getCount();
        return count;
    }
}
  • 싱글톤 빈에서 Provider를 주입받는다.
  • Providerget()으로 원하는 타입의 스프링 빈을 가져온다.(DL)
  • 이때 프로토타입의 빈을 요청하면 스프링 컨테이너는 요청마다 새로운 프로토타입 빈을 생성하여 반환한다.

스프링이 제공하는 기능과 자바 표준의 기능이 공통적인 부분이 있는 경우가 많다. 스프링이 더욱 편리한 기능을 제공하는 경우가 많으므로, 스프링 외에 다른 컨테이너를 사용할 일이 없다면 스프링 기능을 활용하면 된다.

0개의 댓글