스코프(Scope) - 2. 웹 스코프

HYUNBIN CHO·2021년 4월 21일
0

spring

목록 보기
14/23
post-thumbnail

🔷 웹 스코프

웹 환경에서만 동작하는 스코프

🔷 웹 스코프의 특징

프로토타입 스코프와는 다르게 스프링이 해당 스코프의 종료시점까지 관리한다. ➡️ 종료메서드가 호출된다.

🔷 웹 스코프의 종류

🔸 request : HTTP 요청이 들어오고 나갈 때까지 유지되는 스코프, 각각의 HTTP요청마다 별도의 빈 인스턴스가 생성된다.
🔸 session : HTTP session과 동일한 생명주기를 가지는 스코프
🔸 application : 서블릿 컨텍스트와 동일한 생명주기를 가지는 스코프
🔸 websocket : 웹 소켓과 동일한 생명주기를 가지는 스코프

🔸 'spring-boot-starter-web' 라이브러리를 추가하면 스프링 부트는 내장 톰캣 서버를 활용하여 웹 서버와 스프링을 함께 실행시킨다.

🔸 웹 라이브러리가 없으면 AnnotationConfigApplicationContext를 기반으로 애플리케이션을 구동하고, 웹 라이브러리를 추가하면 AnnotationConfigServletWebServerApplicationContext를 기반으로 애플리케이션을 구동한다.

🔷 request 스코프

🔸 동시에 여러 HTTP요청이 오게 되면 어떤 요청이 남긴 로그인지 구분하기가 어렵게 되는데 이럴 때 request스코프를 사용하면 좋다.
🔸 공통포맷 : [UUID][requestURL][message]
🔸 @Scope(value="request") : HTTP요청 시점에 생성되고 요청이 끝나는 시점에 소멸된다.
🔸 스프링 애플리케이션을 실행하는 시점에는 싱글톤 빈은 생성이 가능하지만, 클라이언트의 요청이 없기 때문에 request스코프 빈이 생성되지 않는다. ➡️ 클라이언트의 요청이 올 때까지 이 작업을 뒤로 미루어 둬야 한다.

🔹 해결방법1. Provider

🔸 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()을 호출한다.

🔹 해결방법2. Proxy

@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'

🔸 가짜 프록시 객체는 요청이 오면 그 때 내부의 진짜 빈을 요청하는 위임 로직이 있다.






https://www.inflearn.com/course/스프링-핵심-원리-기본편#

profile
백견이 불여일타

0개의 댓글