Spring Core/02. Spring Container와 빈 관리

06. 빈의 스코프

  • -

이번 포스트에서는 빈의 스코프에 대해 살펴보자.

빈의 스코프(Scope)

 

CoffeeShop  시스템

새롭게 하나의 CoffeeShop을 개업한다고 생각해보자. CoffeeShop에는 Barista가 근무할텐데 이 Barista는 손이 엄청 빠르기 때문에 아무리 많은 주문이 들어와도 순식간에 처리할 수 있다. 즉 맛있게 커피를 만들 수 있는 단 한 명만 필요하다. 그리고 CoffeeShop은 인기가 많아서 엄청나게 많은 Coffee가 팔리고 있다.

이런 CoffeeShop 하나 운영하고 싶네요.

일단 이 일과 관련된 3개의 클래스를 작성해보자.

@Data
@AllArgsConstructor
public class Coffee {
    // Coffee는 stateful 하다.
    private String client;
    private String menu;
}
public class Barista {
    // Barista는 stateless 하다.
    public Coffee makeCoffee(String client, String menu) {
        return new Coffee(client, menu);
    }
}
@Data
public class CoffeeShop {
    private final Barista barista; // Coffeeshop의 의존성

    public Coffee orderCoffee(String client, String menu) {
        return barista.makeCoffee(client, menu);
    }
}

 

@Scope

빈의 스코프란 빈 객체가 어떤 범위까지 존재 할 것인가를 의미하며 스코프에 따라 스프링 컨테이너가 빈 객체를 어떻게 생성하고 관리 할 지를 결정 된다.

Spring에서 빈의 스코프를 지정하기 위해서는 @Scope를 사용한다.

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {
  @AliasFor("value")
  String scopeName() default "";
}

scopeName에는 사용하려는 scope의 이름을 지정하는데 singleton, prototype, request, session, application을 사용한다.

다음은 묵시적 또는 명시적 방식에서 @Scope의 사용 예이다.

// 묵시적 빈 등록 시 scope 지정 : 클래스 레벨에 선언
@Component                    
@Scope("singleton")           // 빈의 기본 scope로 생략 가능
public class CoffeeShop {  ...}

// 명시적 빈 등록 시 scope 지정 : 메서드 레벨에 선언
@Bean(name = "mylPhone") 
@Scope("prototype")
public LPhone lPhone() {
  return new LPhone();
}

각각의 스코프는 어떤 특색이 있는지 살펴보자.

Scope 별 특징

 

singleton

스프링의 빈은 기본적으로 스프링 프레임워크가 비지니스 로직을 재사용 하기위해 관리하는 객체들이다. 이런 빈들은 개별적으로 구분될 필요가 없기 때문에 내부적으로 singleton으로 관리된다. 즉 하나만 만들어서 재사용하는데 이때 사용되는 스코프가 singleton이고 빈의 기본 스코프이다. 따라서 @Scope를 생략하면 singleton으로 동작한다.

CoffeeShop 시스템에서 CoffeeShop이나 Barista는 커피를 판매하거나 커피를 만드는 비지니스 로직만 가지고 있으므로 singleton 타입의 빈으로 적절하다. 

singleton 스코프의 빈을 멀티스레드 환경에서 사용할 때는 주의가 필요하다. 왜냐하면 이 스코프의 빈은 하나의 객체만 생성되기 때문에 여러 스레드가 동시에 이 객체를 공유하면 데이터 충돌이 발생할 수 있다. 이런 문제를 방지하기 위해 singleton 스코프의 빈들은 무상태(stateless)로 설계하는 것이 바람직하다.

prototype

singleton 스코프과 달리 prototype 스코프의 빈은 매번 새로운 객체를 생성한다. 이 스코프는 빈을 재사용하는 것이 목적이 아니고 각각의 빈이 독립적인 상태를 유지해야 하는 경우에 적합하다. 예를 들어 A 손님의 아메리카노와 B 손님의 아메리카노는 서로 다른 Coffee이므로 각각 독립적으로 생성되어야 하며 재사용 될 수 없다. (음식물 재사용은 안됩니다.!)

그렇다면 재사용도 하지 못하는 이런 객체를 왜 빈으로 관리해야 할까? 이유는 스프링의 기능을 활용하기 위해서이다. 빈으로 등록되면, 다른 빈을 주입받거나 보안, 로깅 등의 공통 기능을 AOP를 이용해서 적용할 수 있다.

따라서 그럴 필요가 없다면 굳이 재사용되지 않는 객체를 빈으로 만들 필요는 없다. 1회성의 객체까지 모두 container가 관리하기에는 매번 새로운 객체를 만드는 비용이나 메모리 사용량 증가 등으로 성능상 문제가 될 수도 있다.

request, session, application

request, session, application 스코프는 웹 환경에서 사용되는 스코프로 각각 request, session, application이 유지될 동안 존재하는 빈을 만들어야 할 때 사용된다. 

스코프 생성과 소멸 용도
request HTTP 요청이 들어올 때 생성하고 요청이 끝나면 소멸 각 요청마다 독립적인 빈이 필요한 경우
session HTTP 세션이 시작될 때 생성하고 세션이 종료되면 소멸 사용자(session)별로 독립적인 빈이 필요한 경우
application 웹 애플리케이션이 시작될 때 생성하고 애플리케이션이 종료될 때 소멸 애플리케이션 별로 독립적인 빈이 필요한 경우

대부분 각 영역에서 유지해야 할 상태를 유지하기 위해 사용되는 빈들로 사용하는 이유는 prototype가 유사하다.

CoffeeShop 시스템에서 scope의 지정

앞서 만들었던 클래스를 빈으로 관리해보자. CoffeeShop과 Barista는 singleton 스코프, Coffee는 prototype 스코프를 사용한다. Coffee가 빈이 되었기 때문에 객체 생성시 주의가 필요하다. 스프링에서는 빈을 스프링 컨테이너가 관리해야 한다. 따라서 현재 Coffee를 new 해서 사용하고 있는 Barista는 수정되어야 한다. Barista가 Coffee를 스프링 컨테이너 즉 ApplicationContext에게 요청하도록 코드를 수정해야 한다.

@Component
@RequiredArgsConstructor
public class Barista {
  private final ApplicationContext ctx;  

  public Coffee makeCoffee(String client, String menu) {
    return ctx.getBean(Coffee.class, client, menu);  
  }
}


단위테스트를 통해 빈 객체의 동일성을 확인해보자.

https://inf.run/uTES7

 

참~쉬운 스프링 Part 1. 스프링 프레임워크 이해 및 DI,AOP 강의 | 모두의 코딩:두딩 - 인프런

모두의 코딩:두딩 | 스프링 프레임워크의 핵심을 파고드는 강의로, DI와 AOP를 비롯한 스프링의 중심 개념을 마스터하게 됩니다. 환경 설정부터 단위테스트, 로깅, 메이븐 사용법까지, 스프링 프

www.inflearn.com

 

'Spring Core > 02. Spring Container와 빈 관리' 카테고리의 다른 글

07. 빈의 생명주기  (0) 2024.02.23
05. Profile  (0) 2020.06.17
04. DI 처리 - 묵시적 DI  (0) 2020.06.17
03. DI 처리 - 명시적 DI  (0) 2020.06.16
02. Dependency와 Dependency Injection  (0) 2020.06.15
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.