본문 바로가기
Learning-log/Spring & JPA

(스프링 핵심 원리 - 기본편) 9-(6) request 스코프 예제 만들기 9-(7) 스코프와 Provider (8) 스코프와 프록시

by why제곱 2023. 4. 14.

- request 스코프 예제 만들기

  • gradle에 implement 하기
  •  
  • 동시에 여러 HTTP요청이 오면 정확이 어떤 요청이 남긴 로그인지 구분하기 어려움
    • 이럴 때 사용하기 좋은 것이 request 스코프
    • 로그가 남도록 request 스코프를 활용해서 추가기능 개발하기
    • UUID를 사용해서 HTTP요청 구분해볼것

 

- 스코프와 Provider

  • 코드보기
package hello.core.common;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.UUID;
//로그를 출력하기 위한 MyLogger class
@Component
@Scope(value = "request")
public class MyLogger {

    private String uuid;
    private String requestURL;

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

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

    @PostConstruct
    public void init(){
        uuid = UUID.randomUUID().toString();
        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 lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;

@Controller
@RequiredArgsConstructor
public class LogDemoController {

    private final LogDemoService logDemoService;
    private final ObjectProvider<MyLogger> myLoggerProvider;
    //MyLogger는 request가 들어와서 나갈 때까지만 존재하는 애인데
    //따라서 그 안에 주입하려고 달라 해야하는데 없어!
    //이럴 땐 provider 사용하면 됨.

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

        myLogger.log("controller test");
        logDemoService.logic("testId");
        return "OK";
    }
}
package hello.core.web;

import hello.core.common.MyLogger;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class LogDemoService {

    private final ObjectProvider<MyLogger> myLoggerProvicer;

    public void logic(String id) {

        MyLogger myLogger = myLoggerProvicer.getObject();
        myLogger.log("service id = "+id);
    }
}
  • 결과

 

- 스코프와 프록시

  • 위와 같이 코드 변경
  • CGLIB라는 라이브러리로 내 클래스를 상속 받은 가짜 프록시 객체를 만들어서 주입
  • 결과를 확인해보면 순수한 MyLogger 클래스가 아니라 다른 클래스로 만들어진 객체가 대신 등록 됨
  • 실제 요청이 들어오면 진짜 빔을 요청하는 위임 로직이 가짜 프록시 객체에 들어가 있음
  • 가짜 프록시 객체는 원본 클래스를 상속받아 만들어져 이 객체를 사용하는 클라이언트 입장에서는 원본인지 아닌지 모르게 동일하게 사용 가능함(다형성)
  • 따라서 request scope와 상관없이 싱글톤 처럼 사용가능(실제 싱글톤은 아님. 다른 객체로 동작)
  • 진짜 객체조회를 꼭 필요한 시점까지 지연처리한다는 것이 Provider와 프록시가 가진 공통점