JVM/SpringMVC

빈 스코프: 빈의 생명 주기와 활용

kyoulho 2024. 3. 9. 15:48

스프링 빈 스코프란 무엇일까?


스프링 빈 스코프는 스프링 컨테이너에서 관리되는 빈의 생명 주기와 활용 범위를 정의하는 개념이다. 빈 스코프는 빈이 생성되는 시점, 빈이 사용되는 범위, 빈이 소멸되는 시점 등을 결정한다.

 

스프링 빈 스코프 종류


싱글톤

  • 기본 스코프, 스프링 컨테이너의 시작과 종료까지 유지되는 가장 넓은 범위의 스코프이다.
  • 싱글톤 스코프의 빈을 조회하면 스프링 컨테이너는 항상 같은 인스턴스의 스프링 빈을 반환한다.

프로토타입

  • 스프링 컨테이너는 프로토타입 빈의 생성과 의존관계 주입까지만 관여하고 더는 관리하지 않는 매우 짧은 범위의 스코프이다.
  • 프로토타입 스코프를 스프링 컨테이너에 조회하면 스프링 컨테이너는 항상 새로운 인스턴스를 생성해서 반환한다.
  • 프로토타입 빈을 관리할 책임은 프로토타입 빈을 받은 클라이언트에 있다. 때문에 @PreDestroy 같은 종료 메서드가  호출되지 않는다.

웹 관련 스코프

  • 웹 환경에서만 동작한다.
  • 웹 스코프는 프로토타입과 다르게 해당 스코프의 종료시점까지 스프링이 관리한다.
  • request: HTTP 요청 하나가 들어오고 나갈 때까지 유지되는 스코프, 각각의 HTTP 요청마다 별도의 빈 인스턴스가 생성되고, 관리된다.
  • session: HTTP Session과 동일한 생명주기를 가지는 스코프
  • application: 서블릿 컨텍스트( ServletContext )와 동일한 생명주기를 가지는 스코프
  • websocket: 웹 소켓과 동일한 생명주기를 가지는 스코프

 

빈 스코프 선언


// 자동 등록
@Scope("prototype")
@Component
public class HelloBean {
    // Bean 내용
}

// 수동 등록
@Configuration
public class AppConfig {
    @Bean
    @Scope("prototype")
    public HelloBean helloBean() {
        return new HelloBean();
    }
}

 

스프링 빈 스코프 활용


스프링 빈 스코프는 빈의 생명 주기와 활용 범위를 제어하여 코드의 효율성과 유연성을 높일 수 있다.

다음은 스프링 빈 스코프 활용 예시이다.

스코프 활용
싱글톤  데이터베이스 연결, 서비스 객체 등 애플리케이션 전체에서 공유해야 하는 빈을 생성할 때
프로토타입 매번 새로운 값을 생성해야 하는 빈
예를 들어 랜덤 숫자 생성기 등을 생성할 때
리퀘스트 사용자 요청마다 새 빈을 사용해야 하는 경우
예를 들어 사용자 세션 정보를 저장하는 빈 등을 생성할 때
세션 사용자 세션 동안 유지해야 하는 빈
예를 들어 사용자 장바구니 정보 등을 저장하는 빈 등을 생성할 때
어플리케이션 서버 클러스터 환경에서 모든 서버에서 공유해야 하는 빈
예를 들어 시스템 설정 정보 등을 저장하는 빈 등을 생성할 때

 

프로토타입 빈 사용 시 주의 사항


싱글톤 빈이 프로토타입 빈을 의존하는 경우, 싱글톤 빈은 항상 처음 생성된 프로토타입 빈을 참조하게 된다. 이는 의도하지 않은 동작을 초래할 수 있고 메모리 누수로 이어질 수도 있다.

해결법

1. Provider 패턴 사용

Provider 인터페이스를 사용하여 프로토타입 빈을 요청 시마다 생성할 수 있다. Spring에서는 ObjectProvider를 사용하여 이 패턴을 구현할 수 있다.

@Component
public class SingletonBean {
    private final ObjectProvider<PrototypeBean> prototypeBeanProvider;

    @Autowired
    public SingletonBean(ObjectProvider<PrototypeBean> prototypeBeanProvider) {
        this.prototypeBeanProvider = prototypeBeanProvider;
    }

    public void someMethod() {
        PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
        // 프로토타입 빈을 사용
    }
}

2. FactoryBean 사용

FactoryBean을 사용하여 매번 새로운 프로토타입 빈 인스턴스를 반환할 수 있다.

 
@Component
public class PrototypeBeanFactory implements FactoryBean<PrototypeBean> {
    
    @Override
    public PrototypeBean getObject() throws Exception {
        return new PrototypeBean();
    }

    @Override
    public Class<?> getObjectType() {
        return PrototypeBean.class;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}
@Configuration
public class AppConfig {
    
    @Bean
    public SingletonBean singletonBean() {
        return new SingletonBean();
    }

    @Bean
    public FactoryBean<PrototypeBean> prototypeBean() {
        return new PrototypeBeanFactory();
    }
}

3. 다른 스코프 사용

필요에 따라 다른 스코프를 사용하는 것도 하나의 방법이다.

 

ObjectProvider


Object Provider는 스프링 프레임워크에서 제공되는 빈 주입(Dependency Injection) 도구이다. Object Provider는 빈을 직접 주입하는 대신, 빈을 얻을 수 있는 팩토리를 제공한다. 이를 통해 코드에서 빈을 직접 참조하지 않고도 빈을 사용할 수 있다.

Object Provider의 장점

  • 빈과 코드 사이의 의존성을 분리하여 코드의 유연성을 높인다.
  • 테스트 코드에서 쉽게 빈을 모킹(mocking)할 수 있도록 한다.
  • 코드에서 빈 생성 코드를 제거하여 코드를 간결하게 만들 수 있다.
@Service
public class MyService {

    @Autowired
    private ObjectProvider<MyRepository> repositoryProvider;

    public void doSomething() {
        MyRepository repository = repositoryProvider.getObject();
        // repository를 사용하는 코드
    }
}

 
 

프록시 모드


@Scope 어노테이션의 proxyMode 속성을 사용하여 프록시 모드를 설정할 수 있다. 프록시 모드를 설정하면 빈 스코프가 지정하는 빈 스코프가 지정하는 빈 생성 방식 대신 프록시 객체를 생성하여 주입한다.

@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
// 인터페이스라면 ScopedProxyMode.INTERFACES
public class MyService {
    // ...
}

동작 정리

  • CGLIB 라이브러리를 사용한다.
  • 프록시 객체는 실제 요청이 오면 그때 내부에서 실제 빈을 요청하는 위임 로직이 들어있다.
  • 프록시 객체는 스코프와는 관계가 없다.
  • 내부에 단순한 위임 로직만 있고, 싱글톤 처럼 동작한다.

특징

  • 프록시 객체 덕분에 클라이언트는 마치 싱글톤 빈을 사용하듯이 편리하게 request scope를 사용할 수 있다.
  • Provider를 사용하든, 프록시를 사용하든 핵심 아이디어는 진짜 객체를 조회 시점까지 지연처리 한다는 점이다.

주의점

  • 마치 싱글톤을 사용하는 것 같지만 다르게 동작하기 때문에 결국 주의해서 사용해야 한다.
  • 이런 특별한 scope는 꼭 필요한 곳에만 최소화해서 사용하자, 무분별하게 사용하면 유지보수하기 어려워진다.

 

'JVM > SpringMVC' 카테고리의 다른 글

스프링 이벤트 시스템  (0) 2024.08.10
CORS와 Preflight Request  (0) 2024.03.09
요청 처리와 스레드풀  (0) 2023.12.20
Spring WebSocket & STOMP  (0) 2023.12.15