본문 바로가기
내가 공부하려고 올리는/스프링

빈 스코프

by 결딴력 2022. 2. 6.
반응형

빈 스코프란

  • 스프링 빈은 스프링 컨테이너의 시작과 함께 생성되어 스프링 컨테이너가 종료될 때까지 유지
  • 스프링 빈이 기본적으로 싱글톤 스코프로 생성되기 때문

 

 

스프링이 지원하는 스코프

  • 싱글톤 : 기본 스코프, 가장 넓은 범위의 스코프
  • 프로토타입
    • 프로토타입 빈의 생성과 의존관계 주입까지만 관여
    • 매우 짧은 범위의 스코프
  • 웹 관련 스코프
    • request : 웹 요청이 들어오고 나갈 때까지 유지되는 스코프
    • session : 웹 세션이 생성되고 종료될 때까지 유지되는 스코프
    • application : 웹의 서블릿 컨텍스트와 같은 범위로 유지되는 스코프

 

 

빈 스코프는 다음과 같이 지정

  • 컴포넌트 스캔 자동 등록
@Scope("prototype")
@Component

 

  • 수동 등록
@Scope("prototype")
@Bean
PrototypeBean 클래스이름() {
    return new 클래스이름();
}

 

 

프로토타입 스코프

  • 싱글톤 스코프의 빈을 조회하면 항상 같은 인스턴스의 스프링 빈을 반환
  • 프로토타입 스코프의 빈을 조회하면 스프링 컨테이너는 항상 새로운 인스턴스를 생성해서 반환

 

 

프로토타입 빈 vs 싱글톤 빈

 

싱글톤 빈 요청

  • 싱글톤 스코프의 빈을 스프링 컨테이너에 요청
  • 스프링 컨테이너는 관리하는 스프링 빈을 반환
  • 같은 요청에는 같은 객체 인스턴스의 스프링 빈을 반환

 

프로토타입 빈 요청

 

  • 프로토타입 스코프의 빈을 스프링 컨테이너에 요청
  • 스프링 컨테이너는 요청이 올 때마다 프로토타입 빈을 생성하고, 필요한 의존관계 주입
  • 생성된 빈은 클라이언에 반환되고 더 이상 관리되지 않는다.

 

정리하자면

  • 스프링 컨테이너는 프로토타입 빈을 생성하고, 의존관계 주입, 초기화까지 만을 처리
  • 클라이언트에 프로토타입 빈을 반환하고 더이상 관리하지 않는다.
  • 프로토타입 빈을 관리할 책임은 프로토타입 빈을 받은 클라이언트에 있다.
  • 프로토타입 빈은 반환하고 관리되지 않기 때문에 @PreDestroy 같은 종료 메서드가 호출되지 않는다.

 

 

프로토타입 스코프 - 싱글톤 빈과 함께 사용시 문제점

  • 프로토타입과 싱글톤 빈을 함께 사용할 때 의도와 다르게 동작할 수 있음으로 주의가 필요
  • 예시

  • clientBean싱글톤이므로, 보통 스프링 컨테이너 생성 시점에 함께 생성되고, 의존관계도 주입
  • clientBean의존관계 자동 주입을 사용, 주입 시점에 스프링 컨테이너에 프로토타입 빈을 요청
  • 스프링 컨테이너는 프로토타입 빈을 생성해 clientBean에 반환
  • 프로토타입 빈의 count 필드 값은 0이다.
  • clientBean프로토타입 빈을 내부 필드에 보관(참조값을 보관)

 

  • 클라이언트 A는 clientBean스프링 컨테이너에 요청해서 받는다.
  • clientBean 싱글톤이므로 항상 같은 객체가 반환
  • 클라이언트 A는 clientBean.logic()을 호출
  • clientBeanprototypeBeanaddCount()호출하여 프로토타입 빈의 count를 증가
  • prototypeBean의 count 값은 1이 된다.

 

  • 클라이언트 B는 clientBean스프링 컨테이너에 요청
  • clientBean싱글톤이므로 항상 같은 clientBean이 반환
  • clientBean내부에 가지고 있는 프로토타입 빈은 이미 과거에 주입이 끝난 빈으로
    클라이언트 B의 요청에 따라 새롭게 생성되는 빈이 아니다.
  • 때문에 클라이언트 B가 clientBean.logic()호출하면,
    clientBean prototypeBeanaddCount()호출해서 프로토타입 빈의 count를 증가
  • 원래 count 값이 1이었으므로 count 값은 2가 된다.

 

 

프로토타입 스코프 - 싱글톤 빈과 함께 사용 시 문제 해결법

 

ObjectFactory, ObjectProvider

  • 의존관계를 외부에서 주입받는 것을 DI라고 한다.
  • DI와 다르게 직접 필요한 의존관계를 찾는 것을 Dependency Lookup(DL) 의존관계 조회라 한다.
  • ObjectProvider지정한 빈을 컨테이너에서 대신 찾아주는 DL 서비스를 제공한다.
  • 과거에는 ObjectFactory가 있었는데, 여러 편의 기능을 추가해 ObjectProvider가 만들어졌다.
  • 예시

  • prototypeBeanProvider.getObject()를 통해서 항상 새로운 프로토타입 빈이 생성된다.
  • ObjectProvidergetObject()DL 기능을 제공한다.
  • ObjectFactory와 ObjectProvider의 특징
    • ObjectFactory : 기능이 단순, 별도의 라이브러리 필요 없음, 스트링에 의존
    • ObjectProvider 
      • ObjectFactory에 비해 편의기능이 많다.
      • 별도의 라이브러리 필요없음
      • 스프링에 의존

 

 

JSR-330 Provider

  • ObjectFactory와 ObjectProvider는 모두 스프링에 의존한다.
  • JSP-330 Provider의 경우 자바 표준이기 때문에 스프링이 아닌 다른 컨테이너에서도 사용할 수 있다.
  • 이 방식을 이용하려면 javax.inject:javax.inject:1 라이브러리를 gradle에 추가해야 한다.
  • 예시

  • provider의 get()을 호출하면 DL 기능을 이용할 수 있다.
  • 자바 표준으로 기능이 단순하여 단위 테스트를 만들거나 mock 코드를 만들기 쉽다.
  • 기능은 get() 메서드 하나로 매우 단순하다.
  • 별도의 라이브러리가 필요하다.

 

 

그렇다면 new와 provider get()의 차이점은?

  • provider와 get 메서드의 경우 스프링 컨테이너를 통해 해당 빈을 조회하고,
    조회된 빈을 반환하는 역할을 한다.
  • new의 경우 새로운 객체를 반환하는 역할을 한다.
  • 스프링 컨테이너를 통한다는 것을 제외하면 둘의 결과는 서로 비슷해 보인다.
  • 그렇다면 차이점은 무엇일까?
    • new의 경우 스프링 컨테이너를 통하지 않아 의존관계 주입이 안되고 필요한 초기화도 되지 않는다.
    • provider.get()의 경우 스프링 컨테이너를 통해 의존관계 주입과 초기화가 가능하다.
  • 그렇다면 provider.get()을 쓰는 게 항상 좋은 것일까?
    • 그것은 아니다. 상황에 따라 적절하게 new를 사용해도 가능하다.
    • 김영한 님의 우선순위 정리는 다음과 같다.(참고용)
      1. new로 문제를 해결할 수 있으면 new로 해결한다.
      2. 요청마다 항상 새로운 객체가 필요한데, new를 사용하면 의존관계(@Autowired) 주입이 불가하다.
        의존관계 주입을 객체 생성 시점에 꼭 받아야 한다면 provider.get()을 활용하자.

 

 

웹 스코프

 

 

웹 스코프의 특징

  • 웹 스코프는 웹 환경에서만 동작한다.
  • 웹 스코프는 프로토타입과 다르게 스프링이 해당 스코프의 종료 시점까지 관리
  • 따라서 종료 메서드가 호출된다.

 

 

웹 스코프의 종류

  • request
    HTTP 요청 하나가 들어오고 나갈 때까지 유지되는 스코프
    각각의 HTTP 요청마다 별도의 빈 인스턴스가 생성되고 관리된다.
  • session
    HTTP Session과 동일한 생명주기를 가지는 스코프
  • application
    서블릿 컨텍스트(SevletContext)와 동일한 생명주기를 갖는 스코프
  • websocket
    웹 소켓과 동일한 생명주기를 갖는 스코프

 

 

 

출처 : 인프런 김영한 님 스프링 강의

반응형

댓글