본문 바로가기

언어/- Spring

[ 빈 스코프 ] 웹스코프 / request 스코프 예제 만들기 / 스코프와 Provider / 스코프와 프록시

 

 

웹스코프

 

➡️ 웹 스코프

  🔸웹 환경에서만 동작

  🔸스프링이 해당 스코프의 종료 시점까지 관리 >> 종료 메서드 호출

  🔸request : HTTP 요청 하나가 들어오고 나갈 때까지 유지. 각각의 요청마다 별도의 인스턴스 생성, 관리

  🔸session : HTTP Session과 동일한 생명주기

  🔸application : 서블릿 컨텍스트(ServletContext)와 동일한 생명주기

  🔸websocket : 웹 소켓과 동일한 생명주기

 

 

 

 

request 스코프 예제 만들기

 

 

 

➡️ 웹 라이브러리 gradle에 추가

implementation 'org.springframework.boot:spring-boot-starter-web'

 

  🔸request scope 빈 생성 전에 (웹 리퀘스트가 들어오기 전에) 요청하기 때문에 예외 발생 >> Provider로 해결 가능

package hello.core.common;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import java.util.UUID;

@Component
@Scope("request")
public class MyLogger {
    private String uuid;
    private String requestURL;

    public void setRequestURL(String requestURL) {
        this.requestURL = requestURL;
    }

    public void log(String message){
        System.out.println("[" + uuid + "]" + "[" + requestURL + "]" + message);
    }

    @PostConstruct
    public void init(){
        uuid = UUID.randomUUID().toString(); // UUID 만들어주는 메서드
        System.out.println("[" + uuid + "] request scope bean create:" + this );
    }

    @PreDestroy
    public void close(){
        System.out.println("[" + uuid + "] request scope bean close:" + this );
    }
}
package hello.core.web;


import hello.core.common.MyLogger;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequiredArgsConstructor
public class LogDemoController {
    private final LogDemoService logDemoService;
    private final MyLogger myLogger;

    @RequestMapping("log-demo")
    @ResponseBody
    public String logDemo(HttpServletRequest request){
        String requestURL = request.getRequestURI().toString();
        myLogger.setRequestURL(requestURL);

        myLogger.log("controller test");
        logDemoService.logic("testId");
        return "OK";
    }
}

 

 

 

 

스코프와 Provider

 

➡️ Provider를 사용해 해결

  🔸myLoggerProvider.getObject() 호출 시 점까지 빈의 호출 지연

private final ObjectProvider<MyLogger> myLoggerProvider;
private final ObjectProvider<MyLogger> myLoggerProvider;

 

 

 

 

 

 

스코프와 프록시

 

➡️ proxyMode = ScopedProxyMode.TARGET_CLASS 옵션 추가

  🔸CGLIB라는 라이브러리로 내 클래스를 상속 받은 가짜 프록시 객체를 만들어서 주입

  🔸이 프록시 객체는 실제 요청이 오면 그때 내부에서 실제 빈을 요청하는 위임 로직을 가지고 있음

  🔸덕분에 클라이언트는 마치 싱글톤 빈을 사용하듯 편리하게 request scope 사용 가능

  🔸Provider와 마찬가지로 진짜 객체 조회를 필요한 시점까지 지연 처리

  🔸결국은 싱글톤과 다르게 동작하기 때문에 주의해서 사용해야 함.


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

 

 

 

 

 

 

 

 



* 김영한님의 스프링 핵심 원리 - 기본편을 요약 및 정리한 내용입니다 *

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8