지난 시간에 하나의 인스턴스로 운영되는 싱글턴 빈과 호출을 할 때마다 새로 생성되는 프로토타입 빈에 대해서 학습해 보았다. 이번 시간에는 웹 환경에서 동작하는 웹 스코프에 대해서 김영한 강사님의 강의를 들으며 학습해보자!
목차
빈 스코프란?
프로토타입 스코프
프로토타입 스코프 - 싱글톤 빈과 함께 사용 시 문제점
프로토타입 스코프 - 싱글톤 빈과 함께 사용 시 Provider로 문제 해결
웹 스코프
request 스코프 예제 만들기
스코프와 Provider
스코프와 프록시
1. 웹 스코프
웹 스코프는 웹 환경에서만 동작하며 프로토타입 스코프와 다르게 스프링이 해당 스코프의 종료시점까지 관리한다. 따라서 종료 메서드가 호출된다.
웹 스코프 종류
request: HTTP 요청 하나(요청마다 각각 따로 호출) 가 들어오고 나갈 때 까지 유지되는 스코프, 각각의 HTTP 요청마다 별도의 빈 인스턴스가 생성되고, 관리된다.
session: HTTP Session과 동일한 생명주기를 가지는 스코프
application: 서블릿 컨텍스트(ServletContext)와 동일한 생명주기를 가지는 스코프
websocket: 웹 소켓과 동일한 생명주기를 가지는 스코프
넷 다 범위만 다르지 동작 방식은 비슷하다.
request 스코프 예제 만들기
우리는 request를 사용해 HTTP 요청마다 별도의 빈 인스턴스가 생성되고 관리되는지 logger를 사용해 확인해보겠다. 테스트 결과가 어떻게 나와야 되는지 미리 얘기하면, 우리가 사용할 Controller, Service layer에서 같은 HTTP 요청일 땐 같은 빈 주소를 log로 출력시키면 원하는 결과가 나온 것이다.
bulid.gradle에 추가
web 라이브러리 추가
build.gralde에 위 코드를 추가하고 Run하면 8080 port가 시작됐다는 실행 코드가 나타날 것이다.(그럼 성공)
참고
spring-boot-starter-web 라이브러리를 추가하면 스프링 부트는 내장 톰캣 서버를 활용해 웹 서버와 스프링을 함께 실행시킨다.
스프링 부트는 웹 라이브러리가 없으면 AnnotationConfigApplicationContext를 기반으로, 웹 라이브러리가 있으면 AnnotationConfigServletWebServerApplicationContext를 기반으로 애플리케이션을 구동한다.
(1). 스코프와 Provider
MyLogger(request 스코프 log를 찍어보기 위한 코드)
MyLogger 코드
UUID를 사용해 HTTP 요청을 구분하고, 어떤 URL을 통해 요청이 들어왔는지 requestURL을 통해 확인하는 코드이다.
@Scope(value = "request")를 사용해서 request 스코프로 지정했다. 이제 이 빈은 HTTP 요청 당 하나씩 생성되고, HTTP 요청이 끝나는 시점에 소멸된다.
이 빈이 소멸되는 시점에 @PreDestory를 사용해서 종료 메시지를 남긴다.
requestURL은 이 빈이 생성되는 시점에는 알 수 없으므로, 외부에서 setter로 입력 받는다.
LogDemoController
Controller layer
고객 요청 정보를 받기 위해 HttpServletRequest를 사용했고, 정보 중 requestURL을 추출해 setRequestURL로 MyLogger의 requestURL필드에 값을 삽입했다.
※ ObjectProvider(프로토타입 스코프)를 사용하지 않으면 에러가 발생한다!!
너무나도 간단한 이유다. request 스코프 빈은 HTTP 요청이 시작되야 생성된다. 그런데 아무런 요청도 없이 서버만 Run을 하게 되면 당연히 빈이 생성되지 않아 자동 의존 주입을 할 수 없다. 그래서 에러가 발생한다. 그럼 어떻게 해야되느냐?! 바로 이전 글에서 다루었던 프로토타입 스코프인 ObjectProvider를 사용해 껍데기 빈을 주입시켜 놓은 후, 요청이 들어올 때 빈을 생성해서 사용하면 된다!! 그래서 위 코드에서 ObjectProvider를 사용한 것이다.
LogDemoService
Service layer
Service layer에서도 위와 같은 이유로 ObjectProvider를 사용했다.
테스트 결과
테스트 결과(성공)
ObjectProvider 덕분에 ObjectProvider.getObject()를 호출하는 시점까지 request scope 빈의 생성을 지연할 수 있다.