염몽 개발일지
article thumbnail
Published 2024. 9. 8. 23:43
Spring. 스코프와 프록시 Study/Spring

스코프와 프록시


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

import java.util.UUID;

@Component
//@Scope(value = "request")
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
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();
        System.out.println("[" + uuid + "] request scope bean create: " + this);
    }

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

 

@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS) 처럼 프록시 모드를 사용하면 어떻게 될까?

  • 원래라면 @Scope의 옵션을 request 방식으로 설정하면, 각 request마다 별도의 전용 객체가 생성이 된다.
  • request 요청이 되는 시점에 스프링 컨테이너에서 빈이 생성되기 때문에, 조회를 하려면 lazy 방식을 사용해야한다. 그러므로 ObjectProvider<> 를 사용해야한다.

하지만, ObjectProvider<>를 사용하지 않는 방식이 있다. 그것은 proxyMode 방식이다.

 

proxyMode를 적용하면 MyLogger$$SpringCGLIB$$0 처럼 MyLogger 클래스를 바이트 코드를 조작하여 SpringCGLIB이 위임받는 것을 볼 수 있다.

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

그러므로 싱글톤처럼 스프링 컨테이너 후 자동 주입 시점에 가짜 프록시가 들어오게 되는 것이다.

 

김영한님의 스프링 핵심 원리 강의 - 인프런

 

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

  • 가짜 프록시 객체가 myLogger.log()를 호출하면 내부에서 실제 빈을 요청하는 위임 로직으로 인해 진짜 MyLogger 클래스의 log() 메소드를 호출하는 것이다.
  • 가짜 프록시 객체는 원본 클래스를 상속 받아서 만들어졌기 때문에 이 객체를 사용하는 클라이언트 입장에서는 사실 원본인지 아닌지도 모르게, 동일하게 사용할 수 있다(다형성)

동작 정리

  • CGLIB라는 라이브러리로 내 클래스를 상속 받은 가짜 프록시 객체를 만들어서 주입한다.
  • 이 가짜 프록시 객체는 실제 요청이 오면 그때 내부에서 실제 빈을 요청하는 위임 로직이 들어있다.
  • 가짜 프록시 객체는 실제 request scope와는 관계가 없다. 그냥 가짜이고, 내부에 단순한 위임 로직만 있고, 싱글톤 처럼 동작한다.

요점 정리

  • 사실 Provider를 사용하든, 프록시를 사용하든 핵심 아이디어는 진짜 객체 조회를 꼭 필요한 시점까지 지연처리 한다는 점이다.
  • 단지 애노테이션 설정 변경만으로 원본 객체를 프록시 객체로 대체할 수 있다. 이것이 바로 다형성과 DI 컨테이너가 가진 큰 강점이다.
  • 꼭 웹 스코프가 아니어도 프록시는 사용할 수 있다.

주의 사항

  • 마치 싱글톤을 사용하는 것 같지만 다르게 동작하기 때문에 결국 주의해서 사용해야 한다.
  • 이런 특별한 scope는 꼭 필요한 곳에만 최소화해서 사용하자, 무분별하게 사용하면 유지보수하기 어려워진다.

'Study > Spring' 카테고리의 다른 글

Spring. ObjectProvider  (0) 2024.09.08
Spring. @Configuration  (0) 2024.09.07
Spring. 입문  (0) 2024.08.16
profile

염몽 개발일지

@염몽이

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!