빈 스코프란?

gorapaduckoo·2023년 7월 20일
0

스프링 기본편

목록 보기
9/10
post-thumbnail

인프런 김영한님의 스프링 핵심 원리 - 기본편 강의 내용을 바탕으로 작성한 글입니다.


1. 빈 스코프란?

빈 스코프란, 빈이 생성되어 소멸되기까지의 범위를 의미한다.

지금까지는 스프링 컨테이너가 뜰 때 스프링 빈이 생성되고, 스프링 컨테이너가 종료될 때 함께 소멸한다고 배웠다. 하지만 어플리케이션을 개발하다 보면 다양한 스코프를 가진 빈이 필요해진다.

예를 들어, 클라이언트 요청에 대해 로그를 찍으려면 요청이 들어올 때 빈을 생성하고, 요청이 종료되면 빈을 소멸시켜야 한다. 이처럼 빈의 생명주기를 싱글톤과 다르게 제어할 필요가 있기 때문에, 스프링 컨테이너에서는 다양한 빈 스코프를 지원한다.

빈 스코프에는 다음과 같은 종류가 있다.

  • 싱글톤: 스프링 컨테이너가 시작할 때 생성되어 종료될 때 소멸되는, 스프링 컨테이너와 동일한 생명 주기를 갖는 스코프

  • 프로토타입: 빈의 생성과 의존관계 주입, 초기화까지만 스프링 컨테이너가 관리하고 클라이언트에게 반환되는 스코프이다. 프로토타입 빈은 빈 요청이 들어올 때마다 새로운 인스턴스를 생성하게 된다.

  • 웹 관련 스코프

    • request: 웹 요청이 들어올 때부터 나갈 때까지 유지되는 스코프이다.
    • session: 웹 세션이 생성될 때부터 종료될 때까지 유지되는 스코프이다.
    • application: 웹의 서블릿 컨텍스트와 같은 범위로 유지되는 스코프이다.

    💡서블릿 컨텍스트?
    서블릿들이 공통으로 참조할 수 있는 중앙 데이터 저장소로, 웹 어플리케이션 당 하나가 생성된다. 웹 어플리케이션이 시작될 때 생성되어 종료될 때 소멸한다.


2. 빈 스코프 지정하기

  • 빈 자동 등록 시
@Scope("prototype")
@Component
public class ExampleBean {
	...
  • 빈 수동 등록 시
@Scope("prototype")
@Bean
PrototypeBean ExampleBean() {
	return new exampleBean();
}

3. 싱글톤 스코프

싱글톤 스코프란, 스프링 컨테이너와 동일한 생명 주기를 갖는 스코프로 스프링 컨테이너가 시작할 때 생성되어 종료될 때 소멸된다. 딱 1개의 인스턴스만 생성되어 빈 요청이 들어올 때마다 동일한 인스턴스를 반환하기 때문에 여러 클라이언트가 공유해서 사용하게 된다.

더 자세한 내용은 이전 글을 참고하자.


4. 프로토타입 스코프

프로토타입 스코프란, 빈 요청이 들어올 때마다 새로운 인스턴스를 생성하여 반환하는 스코프이다.

클라이언트가 프로토타입 스코프 빈을 요청하면, 스프링 컨테이너는 프로토타입 빈을 생성하여 의존관계를 주입하고 초기화를 진행한다.

그렇게 만들어진 빈을 클라이언트에게 반환하고 나면 스프링 컨테이너는 더 이상 빈을 관리하지 않는다. 그래서 스프링 컨테이너는 프로토타입 스코프 빈의 소멸 시점에 대해 알 수 없고, @PreDestroy 같은 종료 메서도 호출해주지 않는다. 스프링 컨테이너의 손을 떠난 빈이기 때문이다. 종료 메서드를 호출하고 싶다면 클라이언트가 직접 호출해야 한다.

테스트 코드를 통해 확인해 보자.

  • ExampleBean
public class ExampleBean {

    public ExampleBean() {
        System.out.println("create ExampleBean");
    }
    

    @PostConstruct
    public void init() throws Exception {
        System.out.println("ExampleBean.init");
    }

    @PreDestroy
    public void close() throws Exception {
        System.out.println("ExampleBean.destroy");
    }
}
  • ExampleTest
public class ExampleTest {

    @Test
    public void exampleTest() {
        ConfigurableApplicationContext ac = new AnnotationConfigApplicationContext(ExampleConfig.class);

        // 프로토타입 스코프 빈 요청
        System.out.println("request ExampleBean1");
        ExampleBean exampleBean1 = ac.getBean(ExampleBean.class);
        System.out.println("request ExampleBean2");
        ExampleBean exampleBean2 = ac.getBean(ExampleBean.class);

        // 프로토타입 스코프 빈 출력
        System.out.println("exampleBean1 = " + exampleBean1);
        System.out.println("exampleBean2 = " + exampleBean2);

        ac.close();
    }

    @Configuration
    static class ExampleConfig {
        @Bean
        @Scope("prototype")
        public ExampleBean exampleBean() {
            return new ExampleBean();
        }
    }
}

실행 결과

ExampleBean을 프로토타입 스코프로 지정하고, ExampleBean을 2번 요청하는 테스트 코드를 작성해보았다. 출력 결과에서 요청이 들어올 때마다 새로운 인스턴스가 생성되고, 소멸 메서드는 호출되지 않는 것을 확인할 수 있다.

이번에는 위의 테스트 코드에서 @Scope("prototype") 부분을 지우고 실행해보자.


실행 결과

create가 request보다 먼저 찍힌 것을 확인할 수 있다.
기본 설정인 싱글톤 스코프로 지정되어 스프링 컨테이너 시작과 함께 빈이 생성되었기 때문이다.
exampleBean1exampleBean2가 동일 인스턴스를 참조한다는 것도 확인할 수 있다.
싱글톤 스코프 빈은 딱 1개의 인스턴스만 생성해놓고, 요청이 들어오면 이미 생성해두었던 인스턴스를 반환하기 때문이다.


4. 웹 스코프

웹 스코프는 웹 환경에서 동작하는 웹과 관련된 스코프이다. 스프링 컨테이너에 의해 종료 시점까지 관리되기 때문에 종료 메서드가 호출된다. 스프링에서 지원하는 웹 스코프에는 아래와 같은 것들이 있다.

  • request: HTTP 요청 하나가 들어오고 나갈 때까지 유지되는 스코프. 요청마다 별도의 인스턴스가 생성되고 관리된다.

  • session: HTTP 세션과 동일한 생명주기를 갖는 스코프. 같은 세션 내에서는 동일한 인스턴스가 공유되고, 세션이 종료되면 빈도 함께 소멸된다.

  • application: 서블릿 컨텍스트와 동일한 생명주기를 갖는 스코프. 서블릿 컨텍스트는 웹 어플리케이션 당 1개가 생성되기 때문에 어플리케이션이 시작할 때 생성되고, 종료될 때 소멸된다.

  • websocket: 웹 소켓과 동일한 생명주기를 갖는 스코프. 웹 소켓은 웹 브라우저가 웹 서버와 연결을 시도할 때 생성되어, 웹 페이지를 닫거나 웹 클라이언트/서버 측에서 연결을 종료하면 소멸된다.

    💡 웹 소켓?

    • 웹 어플리케이션에서 양방향 실시간 통신을 구현하기 위해 사용한다. HTTP 요청-응답과 달리 클라이언트가 서버에게 요청하지 않아도 서버가 클라이언트에게 데이터를 보낼 수 있으며, 연결이 유지된다.
    • 생성: 웹 페이지가 로드될 때 클라이언트가 서버와 연결을 시도하며 생성된다.
    • 소멸: 웹 페이지를 닫거나, 클라이언트/서버에서 연결을 종료하면 소멸된다.

자주 사용하는 request 스코프 빈을 통해 웹 스코프 빈의 동작 과정을 살펴보자. 나머지 빈들도 동작 과정은 비슷하다.

클라이언트마다 주문 요청 로그를 찍기 위해 ClientLogger라는 클래스를 request 스코프로 등록해 두었다고 생각해보자.
클라이언트 A와 B가 동시에 주문 요청을 보내면, 스프링은 요청마다 별도의 인스턴스를 생성하여 반환한다. A의 요청과 B의 요청은 서로 다른 ClientLogger 인스턴스를 참조하는데, 클라이언트 A의 요청과 B의 요청은 서로 다른 요청이기 때문이다. request 스코프 빈은 요청 처리가 끝나고 응답이 나가면 파괴된다.

1개의 댓글

comment-user-thumbnail
2023년 7월 20일

정말 유익한 글이었습니다.

답글 달기