이번 편에서는 웹 스코프 빈을 싱글톤 빈에서 안전하게 사용하는 두 가지 대표적인 방식인
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 방식 또는 프록시 방식을 통해 안전하게 사용할 수 있다
'Spring' 카테고리의 다른 글
[Spring 완전 정복 시리즈 - MVC편] 1편 - 웹 애플리케이션의 이해 (7) | 2025.08.02 |
---|---|
[Spring 완전 정복 시리즈] 마지막편 - 기본편 완강 회고 및 마무리 (7) | 2025.08.02 |
[Spring 완전 정복 시리즈] 22편 - 빈 스코프 완전 정복 (2): 웹 스코프와 Provider/프록시 패턴 (0) | 2025.08.01 |
[Spring 완전 정복 시리즈] 21편 - 빈 스코프 완전 정복 (1): 싱글톤과 프로토타입 (0) | 2025.08.01 |
[Spring 완전 정복 시리즈] 20편 - 빈 생명주기 콜백과 초기화 전략 정리 (1) | 2025.07.31 |