새소식

인기 검색어

개인공부/SPRING

spring bean scope

  • -

스프링 빈(Spring Bean)이란?

스프링 IoC(Inversion of Control) 컨테이너에 의해서 관리되고 애플리케이션의 핵심을 이루는 객체들을

스프링 빈(Beans)이라고 한다. 빈은 스프링 컨테이너에 의해서 인스턴스화 되어 조립되고 관리됩니다.

스프링 컨테이너가 관리해준다는 점을 제외하면 자바 객체이다.

 

Singleton

클래스의 인스턴스가 딱 1개만 생성되는 것을 보장하는 디자인 패턴이다.

그래서 객체 인스턴스를 2개 이상 생성하지 못하도록 막아야 한다.

코드에서 private 생성자를 사용해서 외부에서 임의로 new 키워드를 사용하지 못하도록 막아야 한다.

하지만 스프링 컨테이너를 사용하면 컨테이너에 등록되는 빈들을 알아서 싱글톤으로 관리해준다.

 

스프링 핵심 기본원리/김영한

(클라이언트들이 스프링 빈을 요구할 때 같은 참조값을 가진 빈 객체를 반환해준다.)

 싱글톤 패턴에서 주의점

  • 하나의 인스턴스를 생성해서 공유하는 형식이므로 객체의 상태를 유지하게(stateful) 설계하면 안 된다.
  • 특정 클라이언트에 의존적이거나 값을 변경할 수 있는 필드가 있으면 안 된다.
  • 가급적 읽기만 가능해야 한다.
  • 필드 대신 공유되지 않는 지역변수, 파라미터, ThreadLocal을 쓰자.(예를 들어 필드를 반환하는 게 아닌 파라미터를 반환하자)

 

빈 스코프란?

Scope의 뜻대로 빈이 존재할 수 있는 범위를 말한다. 스프링 빈은 기본적으로 싱글톤 스코프가 적용된다.

스프링은 다양한 종류의 스코프를 지원하는데 각 스코프를 분석해보자.

 

1. 싱글톤: 기본 스코프, 스프링 컨테이너의 시작과 종료까지 유지되는 가장 넓은 범위의 스코프

 

2. 프로토타입: 스프링 컨테이너는 프로토타입 빈의 생성과 의존관계 주입까지만 관여하고

더는 관리하지 않는 매우 짧은 범위의 스코프. @Scope("prototype")로 선언한다.

(의존관계까지만 주입하고 보내주기 때문에 @PreDestroy를 볼 수 없음 따라서 프로토타입 범위의 빈을 사용할 때에는 빈 객체의 소멸 처리를 코드에서 직접 해야 한다.)

스프링 핵심 기본원리/김영한

 

싱글톤과 프로토타입 빈을 같이 사용할 때 주의할 점.

우리는 보통 싱글톤과 프로토타입 빈을 같이 사용하게 되는데 여기서 문제가 생긴다.

clientBean은 싱글톤이고 prototypeBean은 프로토타입이고 호출할 때마다 값이 1씩 증가한다고 가정.

싱글톤 빈은 스프링 컨테이너에 등록할 때 의존관계 주입을 위해 PrototypeBean을 요청해서 주입받는다.

이런 방식이면 클라이언트들이 싱글톤인 clientBean을 사용할 때마다 다른 객체가 생성되길 바라는 프로토타입의 효과를 보지 못한다.(이미 주입이 완료된 상태인 싱글톤 빈을 공유해서 사용하기 때문에)

 

PrototypeBean이 공유되어서 count가 공유되어 사용되는 문제가 발생한다.

해결방법

싱글톤 빈과 함께 사용 시 Provider로 문제 해결한다.

ObjectProvider <prototypeBean> Provider를 선언하면

getObject() 메서드를 실행할 때마다 빈을 만들어준다.

(Provider가 직접 의존관계를 찾고 있으므로 Dependency Lookup(DL)이라고 한다.)

 

프로토타입 스코프를 주입받을 때 매번 새로운 스코프를 받기 위해 ObjectProvider를 사용하는 코드로 바꾼 것(오른쪽)

스프링에서 제공하는 ObjectFactory, ObjectProvider를 사용하는 방식도 있고

자바 표준에서 제공하는 JSR-330 Provider를 사용하는 방식도 있다.

 

 

3. 웹 관련 스코프

 

웹 스코프는 웹 환경에서만 동작한다. @Scope("request")로 선언 가능

웹 스코프는 프로토타입과 다르게 스프링이 해당 스코프의 종료 시점까지 관리한다.

따라서 종료 메서드가 호출된다(@PreDestroy,@PostConstruct 둘 다 가능)

 

 

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

request 스코프에서 생각해야 할 점.

request스코프 빈은 HTTP request가 들어와야 생성할 수 있다.

따라서 미리 의존관계를 주입시켜주기 위해 프로토타입에서 활용했던 Provider을 사용하거나

프락시 방식을 써야 한다.

다음과 같이 프락시를 설정해주면 HTTP request의 여부와 상관없이  프록시 클래스를 빈에 미리 주입해 두고 필요할 때마다 사용 가능하게 해 준다.(CGLIB이라는 라이브러리로 바이트코드를 조작해서 가짜 프록시 객체를 넣어놓는다)

 

사실 Provider를 사용하든, 프록시를 사용하든 핵심 아이디어는 진짜 객체 조회를 꼭 필요한 시점까지 지연 처리한다는 점이다.

 

 

스코프 사용 시 주의점

  • 스코프마다 동작 방법이 다르므로 주의해서 사용해야 한다.
  • 특별한 scope는 꼭 필요한 곳에만 최소화해서 사용하자, 무분별하게 사용하면 유지 보수하기 어려워진다
Contents

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

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