웹 환경에서만 동작하는 스코프
프로토타입 스코프와는 다르게 스프링이 해당 스코프의 종료시점까지 관리한다. ➡️ 종료메서드가 호출된다.
🔸 request : HTTP 요청이 들어오고 나갈 때까지 유지되는 스코프, 각각의 HTTP요청마다 별도의 빈 인스턴스가 생성된다.
🔸 session : HTTP session과 동일한 생명주기를 가지는 스코프
🔸 application : 서블릿 컨텍스트와 동일한 생명주기를 가지는 스코프
🔸 websocket : 웹 소켓과 동일한 생명주기를 가지는 스코프🔸 'spring-boot-starter-web' 라이브러리를 추가하면 스프링 부트는 내장 톰캣 서버를 활용하여 웹 서버와 스프링을 함께 실행시킨다.
🔸 웹 라이브러리가 없으면 AnnotationConfigApplicationContext를 기반으로 애플리케이션을 구동하고, 웹 라이브러리를 추가하면 AnnotationConfigServletWebServerApplicationContext를 기반으로 애플리케이션을 구동한다.
🔸 동시에 여러 HTTP요청이 오게 되면 어떤 요청이 남긴 로그인지 구분하기가 어렵게 되는데 이럴 때 request스코프를 사용하면 좋다.
🔸 공통포맷 : [UUID][requestURL][message]
🔸 @Scope(value="request") : HTTP요청 시점에 생성되고 요청이 끝나는 시점에 소멸된다.
🔸 스프링 애플리케이션을 실행하는 시점에는 싱글톤 빈은 생성이 가능하지만, 클라이언트의 요청이 없기 때문에 request스코프 빈이 생성되지 않는다. ➡️ 클라이언트의 요청이 올 때까지 이 작업을 뒤로 미루어 둬야 한다.
🔸 Provider를 이용해서 의존관계 주입을 지연해서 받아서 해결할 수 있다.
@Component @Scope("request") public class MyLogger{ ... } @Service @RequiredArgsConstructor public class LogDemoService{ private final ObjectProvider<MyLogger> myLoggerProvider; public void logic(String id){ MyLogger myLogger = myLoggerProvider.getObject(); myLogger.log("service id = " + id); } } @Controller @RequiredArgsConstructor public class LogDemoController{ private final ObjectProvider<MyLogger> myLoggerProvider; @RequestMapping("log-demo") @ResponseBody public String logDemo(HttpServletRequest request) throws InterruptedException{ String requestURL = request.getRequestURL().toString(); MyLogger myLogger = myLoggerProvider.getObject(); myLogger.setRequestURL(requestURL);
🔸 MyLogger를 직접 주입하는 것이 아니라 ObjectProvider를 통해서 MyLogger를 Lookup할 수 있는 객체가 주입이 된다.
🔸 .getObject()를 하는 시점에 생성이 되고 init()을 호출한다.
@Component @Scope(value="request", proxyMode=ScopedProxyMode.TARGET_CLASS) public class MyLogger{ ... } @Service @RequiredArgsConstructor public class LogDemoService{ public final MyLogger myLogger; public void logic(String id){ ... } } @Controller @RequiredArgsConstructor public class LogDemoController{ private final LogDemoService logDemoService; private final MyLogger myLogger; @RequestMapping("log-demo") @ResponseBody public String logDemo(HttpServletRequest request) throws InterruptedException{ String requestURL = request.getRequestURL().toString(); myLogger.setRequestURL(requestURL); ... } }
🔸 LogDemoService, LogDemoController의 코드는 Provider를 사용하기 전과 동일
🔸 @Scope에 proxyMode를 설정하면 스프링 컨테이너는 CGLIB이라는 바이트코드를 조작하는 라이브러리를 사용하여 MyLogger를 상속받은 가짜 프록시 객체를 생성한다.
🔸 스프링 컨테이너에 myLogger라는 이름으로 가짜 프록시 객체를 등록한다.ac.getBean("myLogger", MyLogger.class)로 조회 ➡️ 'MyLogger$ $EnhancerBySpringCGLIB'
🔸 가짜 프록시 객체는 요청이 오면 그 때 내부의 진짜 빈을 요청하는 위임 로직이 있다.