본문 바로가기
강의 실습/스프링 핵심 원리 - 기본편

스코프와 프록시

by jint 2026. 5. 12.

프록시 방식을 사용

 

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


· proxyMode = ScopedProxyMode.TARGET_CLASS
적용 대상이 클래스면, TARGET_CLASS
적용 대상이 인터페이스면, INTERFACES

· MyLogger 의 가짜 프록시 클래스를 만들어 다른 빈에 미리 주입 가능 (HTTP request 와 상관 없이 주입 가능)

ObjectProvider 적용 이전으로 코드를 돌린다.

- src/main/java/hello/core/web/LogDemoController.java

package hello.core.web;

import hello.core.common.MyLogger;
import hello.core.logdemo.LogDemoService;
import jakarta.servlet.http.HttpServletRequest;
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;

@Controller
@RequiredArgsConstructor
public class LogDemoController {

    private final LogDemoService logDemoService;
    private final MyLogger myLogger;
    // private final ObjectProvider<MyLogger> myLoggerProvider;

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

        myLogger.log("controller test");
        // Thread.sleep(1000);
        logDemoService.logic("testId");

        return "OK";
    }

}


- src/main/java/hello/core/logdemo/LogDemoService.java

package hello.core.logdemo;

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 MyLogger myLogger;
    // private final ObjectProvider<MyLogger> myLoggerProvider;

    public void logic(String id) {
        // MyLogger myLogger = myLoggerProvider.getObject();
        myLogger.log("service id = " + id);
    }

}


CoreApplication 에서 main() 메서드로 스프링을 실행하고 브라우저에서 http://localhost:8080/log-demo 로 접속한다.

- 콘솔

[134c70a6-b533-49bd-9204-66154384e9fc] request scope bean create: hello.core.common.MyLogger@c3fa824
[134c70a6-b533-49bd-9204-66154384e9fc][http://localhost:8080/log-demo] controller test
[134c70a6-b533-49bd-9204-66154384e9fc][http://localhost:8080/log-demo] service id = testId
[134c70a6-b533-49bd-9204-66154384e9fc] request scope bean close: hello.core.common.MyLogger@c3fa824



1. 웹 스코프와 프록시 동작 원리
주입된 myLogger 를 확인한다.

- src/main/java/hello/core/web/LogDemoController.java

...
        String requestURL = request.getRequestURL().toString();
        // MyLogger myLogger = myLoggerProvider.getObject(); // request 빈 생성
        System.out.println("myLogger = " + myLogger.getClass());
        myLogger.setRequestURL(requestURL);
...


- 콘솔

myLogger = class hello.core.common.MyLogger$$SpringCGLIB$$0


CGLIB 라이브러리로 원본 클래스(MyLogger)를 상속 받은 가짜 프록시 객체를 만들어서 주입

· @Scope 의 proxyMode = ScopedProxyMode.TARGET_CLASS 설정시, 스프링 컨테이너는 CGLIB 라는 바이트 코드를 조작하는 라이브러리를 사용해 원본 클래스(MyLogger)를 상속받은 가짜 프록시 객체를 생성한다.
따라서 의존관계 주입시, 가짜 프록시 객체가 주입된다.

· 콘솔에도 직접 등록한 MyLogger 클래스가 아닌 CGLIB 라이브러리로 만들어진 객체가 대신 등록된 것을 확인할 수 있다.
스프링 컨테이너에 "myLogger" 이름으로 가짜 프록시 객체가 등록됨
ac.getBean("myLogger", MyLogger.class) 로 조회해도 가짜 프록시 객체가 조회됨

 

웹 스코프와 프록시 동작 원리


가짜 프록시 객체는 요청이 오면 그 때 내부에서 진짜 빈을 요청하는 위임 로직이 들어있음
실제 request 스코프와는 관계 없이, 내부에 단순 위임 로직만 있고, 싱글톤처럼 동작함

· 가짜 프록시 객체 내부에 "myLogger" 를 찾는 방법을 알고 있다.
클라이언트가 myLogger.log() 호출시, 가짜 프록시 객체 메서드를 호출한 것이다.
가짜 프록시 객체는 request 스코프의 진짜 myLogger.log() 를 호출한다.

· 가짜 프록시 객체는 원본 클래스를 상속받아 만들어졌기 때문에, 이 객체를 사용하는 클라이언트 입장에서는 원본인지 아닌지도 모르게 동일하게 사용 가능(다형성)
프록시 객체 덕분에 클라이언트는 싱글톤 빈을 사용하듯 편리하게 request scope 사용 가능


2. 핵심
#1 Provider 를 사용하든, 프록시를 사용하든 핵심 아이디어는 진짜 객체 조회를 꼭 필요한 시점까지 지연처리 한다는 점!
#2 어노테이션 설정 변경만으로 원본 객체를 프록시 객체로 대체 : 다형성, DI 컨테이너가 가진 큰 강점
#3 웹 스코프가 아니어도 프록시 사용 가능


3. 주의점
#1 싱글톤을 사용하는 것 같지만 다르게 동작하기 때문에 주의해서 사용해야 함 (request 요청마다 따로 생성됨)
#2 이렇게 특별한 scope는 꼭 필요한 곳에 최소화해서 사용
무분별하게 사용시, 유지보수 어려워짐


참고링크 : 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?cid=325969

 

스프링 핵심 원리 - 기본편| 김영한 - 인프런 강의

현재 평점 5.0점 수강생 49,609명인 강의를 만나보세요. 스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다. 스프링 기본 기능, 스프

www.inflearn.com

댓글