본문 바로가기
Spring/스프링 핵심 원리 - 기본편

9-2. 빈 스코프 : 웹 스코프

by hk27 2022. 1. 13.

 

HTTP 요청마다 빈을 생성할 수는 없나요?

 

안녕하세요.

오늘은 빈 스코프 중에서 웹 스코프에 대해 알아보겠습니다. 

 

빈 스코프는 빈이 존재할 수 있는 범위로, 싱글톤, 프로토타입, 웹 스코프 3개로 나눌 수 있습니다.

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

프로토타입은 클라이언트의 요청이 들어오면 생성되고, 스프링 컨테이너는 빈의 생성, 의존 관계 주입, 초기화까지만 관여하고 더는 관리하지 않는 스코프입니다.

프로토타입 스코프는 아래 게시글에서 알아보았으니 궁금하신 분은 참고해주세요!

https://passionate.tistory.com/26

 

9-1. 빈 스코프: 프로토타입 스코프

스프링 빈은 싱글톤으로만 관리되나요? 안녕하세요. 스프링 빈의 스코프가 무엇인지 알아보고, 그 중 프로토타입 스코프에 대해서 자세히 살펴보겠습니다. 빈 스코프 https://passionate.tistory.com/13

passionate.tistory.com

 

웹 스코프

오늘은 세 번째인 웹 스코프를 알아보겠습니다.

웹 스코프는 말 그대로 웹에 관련된 스코프로, 웹 환경에서만 동작합니다.

프로토타입 스코프와 다르게 스프링이 해당 스코프의 종료 시점까지 관리하고, 종료 메소드가 호출됩니다.

 

웹 스코프는 4가지 종류가 있습니다. 

1) request: HTTP 요청 하나가 들어오고 나갈 때까지 유지되는 스코프로, 각각의 HTTP 요청마다 별도의 빈 인스턴스가 생성되고, 관리됩니다. 

2) session: HTTP Session과 같은 생명주기를 가지는 스코프입니다. 

3) application: 서블릿 컨텍스트와 같은 생명주기를 가지는 스코프입니다.

4) websocket: 웹 소켓과 같은 생명주기를 가지는 스코프입니다.

 

여기서는 request 스코프를 중심으로 살펴보겠습니다.

나머지도 범위만 다르고 동작 방식은 비슷합니다.

 

request 스코프 

request 스코프는 위의 사진처럼 HTTP request 요청 당 각각 1개씩 할당됩니다.

한 HTTP request를 처리할 때는, 한 개의 빈이 유지됩니다.

예를 들어서 클라이언트 A가 특정 HTTP request를 요청하면, controller와 service가 동작한다고 가정합시다.

controller와 service가 request scope를 갖는 객체 'MyLogger'를 의존관계 주입 받는다면, MyLogger 객체는 1개가 생성되어서 controller와 service에 같은 객체가 주입됩니다.

클라이언트 B가 HTTP request 요청을 보내면 다른 MyLogger 객체가 형성됩니다. 

 

그런데 생각해보면, Controller와 Service가 싱글톤 스코프이면 스프링 컨테이너가 생성될 때 스프링 빈이 만들어지고, 의존 관계가 주입됩니다. 의존 관계가 주입될 때 MyLogger 객체가 필요하고요.

그러나 request 스코프를 갖는 객체는 사용자 요청이 서버에 들어올 때 빈이 생성됩니다.

즉, 사용자 요청이 들어오기 전에는 request 스코프를 갖는 빈이 존재합니다.

이런 경우 Controller와 Service는 의존 관계 주입을 받을 수 없습니다. 이 문제를 해결하는 것이 프록시입니다.

 

프록시(proxy)

프록시는 대리인, 대용물이라는 의미를 가집니다. 스코프에서 프록시는 가짜 프록시 객체를 만들어서 빈의 생성을 지연하는 데 사용됩니다. 아래 코드처럼 사용할 수 있습니다.

@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyLogger {
}

이렇게 하면 MyLogger의 가짜 프록시 클래스를 만들어두고 스프링 컨테이너에 등록하며, 의존 관계 주입으로 MyLogger가 필요할 때 가짜 프록시 클래스를 다른 빈에 미리 주입해둘 수 있습니다.

그리고 실제로 MyLogger의 기능이 필요하면 진짜 MyLogger 객체를 찾아서 동작합니다. 

아래 사진과 같이 동작하는 것입니다.

MyLogger 프록시 객체가 스프링 빈으로 등록되어 있으며, 의존 관계 주입도 이 빈으로 작동됩니다.

가짜 프록시 객체는 요청이 오면 내부에서 진짜 빈을 요청하는 위임 로직이 들어있습니다. 

MyLogger를 사용하는 로직이 호출되면 그때 MyLoggerProxy 객체가 진짜 MyLogger를 호출해줍니다. 

 

핵심 아이디어는 진짜 객체를 조회하는 것을 꼭 필요한 시점까지 지연처리 한다는 것입니다.

이렇게 사용하면 처음에 요청이 들어오지 않아서 request scope인 스프링 빈이 등록되지 않아도 의존 관계를 주입해줄 수 있습니다. 

꼭 웹 스코프가 아니어도 프록시는 사용할 수 있습니다.

 

웹 스코프처럼 특별한 스코프는 꼭 필요한 곳에서만 최소화해서 사용하고, 기본값인 싱글톤 빈을 사용하는 것이 좋습니다.

같은 클래스의 스프링 빈 여러 개가 형성되어서 유지 보수하기 어렵기 때문입니다. 

 

 

인프런  '스프링 핵심 원리 - 기본편' 강의를 듣고 공부하며 정리한 자료입니다. 

잘못된 부분은 피드백 주시면 감사하겠습니다. 

글 읽어주셔서 감사합니다 :-)

 

참고자료

[1] 스프링 핵심 원리 - 기본편, 섹션 9. 빈 스코프 https://www.inflearn.com/course/스프링-핵심-원리-기본편

 

 

 

댓글