Spring

[Spring 완전 정복 시리즈] 23편 - 빈 스코프 완전 정복 (3): Provider vs 프록시, 그리고 정리

dev-nadan 2025. 8. 1. 13:53

이번 편에서는 웹 스코프 빈을 싱글톤 빈에서 안전하게 사용하는 두 가지 대표적인 방식

Provider 방식과 프록시 방식을 비교하며 각각의 작동 원리와 장단점을 정리한다.

마지막으로 지금까지 학습한 빈 스코프의 핵심 포인트를 복습 퀴즈와 함께 정리해보자.


1. 싱글톤 빈에서 웹 스코프 빈을 사용하는 문제

@Scope(value = "request")
@Component
public class MyLogger { ... }

@Controller
@RequiredArgsConstructor
public class LogDemoController {
    private final MyLogger myLogger; // X 오류 발생 가능
}

 

  • MyLogger는 요청 스코프이지만, LogDemoController는 싱글톤 스코프이다
  • 스프링 컨테이너가 시작될 때 request 스코프 빈이 없기 때문에 오류 발생

2. 해결책 ①: ObjectProvider를 통한 DL(Dependency Lookup)

@Controller
@RequiredArgsConstructor
public class LogDemoController {
    private final ObjectProvider<MyLogger> myLoggerProvider;

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

 

  • getObject()를 호출하는 실행 시점에 스프링이 실제 빈을 찾아줌
  • request 스코프 빈도 안전하게 사용할 수 있음
  • 의존성 주입 시점이 아닌 런타임에 직접 조회하는 방식(DL)

JSR-330 표준 Provider

@Inject
private Provider<MyLogger> provider;

MyLogger logger = provider.get();

 

  • javax.inject.Provider자바 표준 DL 방식
  • 스프링 외 다른 프레임워크와의 호환성을 고려하면 유리함
  • 단점: 사용하려면 의존성(jakarta.inject)을 직접 추가해야 함

3. 해결책 ②: 프록시(proxyMode = TARGET_CLASS) 사용

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

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

    @RequestMapping("log-demo")
    @ResponseBody
    public String logDemo(HttpServletRequest request) {
        myLogger.setRequestURL(request.getRequestURL().toString());
        myLogger.log("controller test");
        return "OK";
    }
}

 

작동 원리

  • 프록시 객체를 싱글톤 빈에 미리 주입
  • 실제 사용 시점에 현재 요청에 맞는 진짜 request 스코프 빈으로 위임
  • 코드는 평소와 동일하게 유지됨

Provider vs Proxy 비교

항목 ObjectProvider / Provider 프록시
주입 시점 실제 빈 주입되지 않음 (DL) 프록시 객체가 주입됨
사용 시점 getObject() 호출 시 생성 메서드 호출 시 자동 위임
코드 영향 getObject() 호출 필요 일반 빈처럼 사용 가능
테스트 용이성 상대적으로 유연함 DI 대상이 프록시이므로 주의 필요
추천 용도 조건부 호출, 명확한 생성 시점 필요 코드 간결성, 사용 편의성 필요할 때

4. 실무에서는?

  • 대부분의 빈은 싱글톤 스코프로 해결된다
  • 프로토타입/웹 스코프는 특정 상황에서만 사용되고, 그마저도 거의 Provider나 프록시로 해결
  • 프록시는 코드가 깔끔해지고, Provider더 명시적인 제어가 가능함

5. 복습하기

Q1. 프로토타입 빈은 언제 destroy되나요?

  • X: 스프링 컨테이너는 destroy하지 않음
  • O: 클라이언트 코드에서 직접 종료 처리를 해야 함

Q2. 여러 HTTP 요청이 동시에 들어오면 request 스코프 빈은 어떻게 동작하나요?

  • 각 HTTP 요청마다 별도의 인스턴스가 생성되고 종료됨

Q3. 싱글톤 빈에 프로토타입 빈을 주입하면 생기는 문제는?

  • 프로토타입 빈이 한 번만 주입되고 계속 재사용되어 원래 의도와 다르게 동작

Q4. Provider 또는 프록시 방식의 핵심 원리는?

  • 의존성 조회 시점을 지연시켜, 스코프가 활성화된 이후에 빈을 생성하게 함

Q5. 프록시 방식의 장점은?

  • 일반 빈처럼 사용할 수 있어 코드가 간결해지고 테스트도 쉬워짐

마무리

  • 스코프를 통해 스프링 빈의 생존 범위를 제어할 수 있으며, 기본은 싱글톤이다
  • 프로토타입 스코프는 매번 새로운 객체가 필요할 때 사용하며 종료는 직접 관리해야 한다
  • 웹 스코프(request, session)는 HTTP 요청과 세션 생명주기와 연결된다
  • 스코프 빈을 싱글톤 빈에서 사용할 땐 Provider 방식 또는 프록시 방식을 통해 안전하게 사용할 수 있다