[spring] proxy 사용하기

괭이밥·2022년 11월 20일

spring

목록 보기
8/10
post-thumbnail

🔎 목차

  1. proxy 란?
  2. proxy 예제


🍃 proxy란?

가짜 객체

  • @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
  • 이 객체는 사용하기 전까지 가짜 프록시 객체 클래스를 만들어둔다.
  • 이후 직접 사용할 때 진짜 클래스를 찾아 사용한다.
  • ScopedProxyMode
    클래스단위: TARGET_CLASS
    인터페이스: INTERFACE

언제 사용?

  • 지금 당장 사용하진 않지만 스프링 빈에 등록하고 의존관계에 필요할 때 사용한다.
  • 주로 프로토타입 빈, 웹 빈에서 사용한다.

아래 예시는 request 빈을 이용한 예시이다.

Requestbean

  • @Scope(value = "request")
  • request 빈이다.
  • 초기화 콜백
    • UUID를 사용하여 초기화한다.
    • uuid: unique id
  • 소멸 콜백으로 request 사용이 끝나는 것을 명시
  • logic
    • 현재 클래스를 출력한다.
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.UUID;

@Component
@Scope(value = "request")
public class RequestBean {
    private String uuid;

    @PostConstruct
    public void init(){
        String uuid = UUID.randomUUID().toString();
        System.out.println("[" + uuid+ "]" + " start");
    }

    @PreDestroy
    public void destroy(){
        System.out.println("[" + uuid+ "]" + " close");
    }

    public void logic(){
        System.out.println(this);
    }
}

Controller

  • /test로 들어오면 requestService를 실행한다.
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class RequestController {

    private final RequestService requestService;

    public RequestController(RequestService requestService) {
        this.requestService = requestService;
    }


    @RequestMapping("test")
    @ResponseBody
    public String test(){
        requestService.logic();
        return "OK";
    }
}

Service

  • requestBean을 접근하여 로직을 호출한다.
import org.springframework.stereotype.Service;

@Service
public class RequestService {
    private final RequestBean requestBean;


    public RequestService(RequestBean requestBean) {
        this.requestBean = requestBean;
    }

    public void logic(){
        requestBean.logic();
    }
}

실행결과 - 오류발생

  • requestBean 실행할 수 없다.
    • requestBean은 request 요청이 들어와야 생성되고 사용되기 때문이다.
  • proxy 사용 권장하는 것을 볼 수 있다.
Error creating bean with name 'requestBean': 
Scope 'request' is not active for the current thread; 
consider defining a scoped proxy for this bean if you intend to refer to it from a singleton;

이 문제는 provider로 해결할 수 있다.
provider와 proxy는 모두 객체를 사용하기 전까지 다른 것으로 대체하고 실제 하용할 때 접근한다.(지연처리) 아래는 프록시로 해결한 모습이다.
Service 코드

  • requestBean을 provider로 받아온다.

🍃 proxy 예제

requestBean 수정

  • @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
  • 적용 대상이 클래스 단위이므로 TARGET_CLASS 사용
@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestBean {
    // 위와 동일
}

실행 결과

  • localhost:8080/test로 들어가서 requestBean 호출을 본다.
  • requestBean 출력 -> CGLIB$$e024bbed가 붙은 것을 볼 수 있다.
  • 바이트 코드를 조작하여 가짜 객체를 만들어 미리 심어놓는다.
[88c79a86-7308-4bdd-a18f-78aae4ebbc32] start
test.core.request.RequestBean@7b02f558class test.core.request.RequestBean$$EnhancerBySpringCGLIB$$e024bbed
[null] close



출처
인프런 '스프링 핵심 원리 - 기본편' 강의

profile
개발도 하고 싶은 클라우드 엔지니어

0개의 댓글