FireDrago

[Spring] 빈 스코프 본문

카테고리 없음

[Spring] 빈 스코프

화이용 2024. 1. 14. 17:16

빈 스코프란

 

스프링 빈은 스프링 컨테이너에 생성되고 존재범위를 가진다. 이를 빈 스코프라고 한다. 가장 많이 사용되는 '싱글턴' 빈의 경우 스프링 컨테이너의 소멸까지 빈이 존재한다. 스프링은 여러가지 빈 스코프를 제공한다.

- 싱글톤(singleton): 스프링 컨테이너의 시작과 종료까지 유지되는 가장 넓은 범위의 스코프. 싱글톤 스코프의 빈은 스프링 컨테이너가 단 하나만 생성하고, 모든 클라이언트가 동일한 인스턴스를 공유한다.


- 프로토타입(prototype): 스프링 컨테이너는 프로토타입 빈의 생성과 의존 관계 주입까지만 관여하고, 더는 관리하지 않는 매우 짧은 범위의 스코프. 프로토타입 스코프의 빈은 클라이언트가 요청할 때마다 새로운 인스턴스가 생성된다.


- 웹 관련 스코프
  - request: 웹 요청이 들어오고 나갈 때까지 유지되는 스코프
  - session: 웹 세션이 생성되고 종료될 때까지 유지되는 스코프
  - application: 웹의 서블릿 컨텍스와 같은 범위로 유지되는 스코프

 

스코프 사용법은 다음과 같다

스코프를 부여할 빈에 @Scope 애너테이션을 붙인다

 

프로토타입 

 

프로토타입 스코프는 싱글턴과 달리 클라이언트가 요청 할때마다 새로운 인스턴스가 생성된다. 만약 싱글턴 빈이 

인스턴스 변수로 프로토타입의 빈을 주입받게 되면 어떻게 될까?

 

 

- ClientBean 클래스는 싱글턴 빈이면서 인스턴스 변수로 프로토타입 스코프 PrototypeBean을 가지고 있다.

ClientBean의 logic 메서드를 실행하면 PrototypeBean의 count 는 어떻게 변할까?

프로토타입 스코프라면 실행할때마다 새로운 빈이 생성되므로 매번 1이라는 값이 나와야 할것이다. 

하지만 테스트 코드를 보면 그렇지 않다. ClientBean이 생성될때 만들어진 PrototypeBean이 그대로 유지되는 것이다.

 

PrototypeBean은 새로 생성되지 않고 싱글턴 안에 주입되어 유지된다.

 

 

ObjectProvider 사용하여 해결

 

싱글턴과 프로토타입이 함께 사용될때는 ObjectProvider를 사용한다.

 

 

- ClientBean을 다음처럼 변경하게되면  최초에 의존성을 주입할때는 PrototypeBean을 가져올 수있는 기능을 가진 

ObjectProvider 객체를 주입한다. 그리고 logic 메서드가 실행될때 PrototypeBean을 스프링 컨테이너로 부터 가져온다.

이렇게 되면 Prototype 객체는 그 의미에 맞게 매번 새로운 인스턴스가 생성된다. 인스턴스 주입단계에서 사용할때로 

인스턴스 생성이 지연 되는 것이다.

테스트도 매번 1로 새로운 객체가 사용됨을 알 수 있다.

 

웹 스코프

웹 스코프는 웹 환경에서만 동작한다. 웹 스코프는 프로토타입과 다르게 해당 스코프의 종료시점까지 관리한다.

종료 메서드가 호출된다.

 

 <웹스코프 종류>

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


<Request 스코프 예제 만들기>

 

@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)

 

이 부분을 주목하자 proxyMode = ScopedProxyMode.TARGET_CLASS  속성을 사용하면

아직 request 요청이 들어오지 않아서 생성되지 못하는 빈 대신 프록시 빈을 대신 생성한다.

CGLib 라이브러리는 바이트코드를 조작하여 프록시 객체를 생성한다.

이 프록시빈은 MyLogger 를 상속받은 빈이며 내부에 MyLogger 메서드를 호출하는 방법을 알고있다.

따라서 request 요청이 들어와 MyLogger 빈이 필요해지면, 그때 MyLogger 메서드를 호출한다.