빈 스코프 : 빈이 존재할 수 있는 범위
- 싱글톤 : 기본 스코프. 스프링 컨테이너의 시작 ~ 종료까지 유지되는 가장 넓은 범위의 스코프
- 빈 조회 시 스프링 컨테이너는 항상 같은 인스턴스의 스프링 빈 반환
- 프로토타입 : 빈 생성 ~ 의존관게 주입까지만 관여. 매우 짧은 스코프
- 빈 조회 시 스프링 컨테이너는 항상 새로운 인스턴스를 생성해서 반환
- 프로토타입 빈을 관리할 책임 --> 프로토타입 빈을 받은 클라이언트에 있다
- @Predestory 등 메서드 불가능
- 종료를 직접 입력해야함 (ex : Prototype.destory)

Singleton은 같은 주소를 사용하는 반면, Prototype은 새로운 주소를 발급함.
- @Scope("singleton" or "prototype")에서 설정하면 됨
프로토타입 스코프를 싱글톤 빈과 함께 사용할 때
- 싱글톤 빈은 생성 시점에만 의존관계 주입을 받음 --> 프로토타입 빈이 생성되긴 하지만, 싱글톤 빈과 함께 계속 유지됨
- 따라서 싱글톤 빈이 프로토타입을 사용할 때마다 스프링 컨테이너에 새로 요청
--> 지정한 프로토타입 빈을 컨테이너에서 대신 찾아주는 DL(의존관계 조회) 기능을 제공하면 됨
* ObjectProvider : 원할 때 언제든지 스프링 컨테이너에서 빈 대신 꺼내주는 역할
- 기능이 단순하기 때문에, 단위테스트를 만들거나 mock 코드를 만들기가 쉬워짐
- ObjectFactory 상속, 옵션, 스트림 처리 등 편의 기능이 많고, 별도의 라이브러리 필요 없음. 또한 스프링에 의존함
* JSR-330 Provider : ObjectProvider과는 다르게 스프링에 의존하지 않는 방법
(build.gradle에 implementation 'jakarta.inject:jakarta.inject-api:2.0.1' 입력)
(import jakarta.inject.Provider 입력 후 실행)
- get() 메서드 하나로 기능이 단순함
- 별도 라이브러리 필요함
- 자바 표준이기 때문에, 스프링이 아닌 다른 컨테이너에서도 사용 가능함
그렇지만 실무에서는 싱글톤 빈으로 대부분 문제 해결되기 때문에 프로토타입 빈을 직접적으로 사용할 일은 드물다
웹 스코프
- request : 웹 요청이 들어오고 나갈 때까지 유지
- session : 웹 세션 생성 ~ 종료될 때까지 유지
- application : 웹의 서블릿 컨텍스와 같은 범위로 유지
동시에 여러 개의 HTTP 요청이 올 때 로그가 섞여서 들어와서 정확히 어떤 요청이 남긴 로그인지 구분이 어려움
--> request 스코프를 활용 : UUID를 사용하여 HTTP 요청 구분
- @Scope(value = "request")로 스코프 지정
- HTTP 요청 당 하나씩 생성 & 요청이 끝나는 시점에 소멸된다
- requestURL은 빈이 생성되는 시점을 알 수 없음 --> setter로 외부에서 입력 받아야 함
| [47b79cd2-f36b-47f7-8d70-d3f2cbe76588] request scope bean create : hello.core.common.MyLogger@6e492664 [47b79cd2-f36b-47f7-8d70-d3f2cbe76588][http://localhost:8080/log-demo] controller test [47b79cd2-f36b-47f7-8d70-d3f2cbe76588][http://localhost:8080/log-demo] service id = testId [47b79cd2-f36b-47f7-8d70-d3f2cbe76588] request scope bean close : hello.core.common.MyLogger@6e492664 [1e9aaae1-2e3c-47c1-b8d9-6b461156d2a6] request scope bean create : hello.core.common.MyLogger@ab551f3 [1e9aaae1-2e3c-47c1-b8d9-6b461156d2a6][http://localhost:8080/log-demo] controller test [1e9aaae1-2e3c-47c1-b8d9-6b461156d2a6][http://localhost:8080/log-demo] service id = testId [1e9aaae1-2e3c-47c1-b8d9-6b461156d2a6] request scope bean close : hello.core.common.MyLogger@ab551f3 |
- 로그 관리가 id별로 잘 된 것을 볼 수 있음
* Proxy
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
- Class인 경우 : TARGET_CLASS, 인터페이스인 경우 : INTERFACES
- 서버가 뜨는 시점에서 Controller는 MyLogger를 주입받으려고 함
- 그러나 서버 뜨는 시점에는 사용자의 HTTP 요청이 없기 때문에 객체 자체가 생성이 되지 않음
- 따라서 가짜 객체를 생성한 후 이를 주입하여 지연을 로딩한 이후 진짜 객체 요청을 호출한다.
- 코드 간결 : .getObject()를 매번 호출할 필요가 없음
- 싱글톤처럼 사용 가능
- 다형성 : 가짜 객체가 진짜 객체를 상속받음 --> 사용하는 쪽에서는 진짜인지 가짜인지 모르고 동일하게 사용 가능
따라서 프록시 모드를 사용하는 경우 스프링이 가짜 객체를 미리 주입해둔 후, 실제 요청이 들어오는 시점에만 진짜 객체를 연결
--> 생존기간이 다른 빈 사이의 의존관계 문제를 해
식당에서 예약석을 잡아놓고, 이후 실제 손님이 오는 경우 주문을 받는 것으로 이해하면 쉽다
'공부 > spring' 카테고리의 다른 글
| [HTTP] HTTP 특징 (0) | 2026.04.27 |
|---|---|
| [HTTP] Internet Network, URI (0) | 2026.04.27 |
| [Spring] Bean Lifecycle Callback (0) | 2026.04.24 |
| [Spring] 의존관계 자동주입 (0) | 2026.04.23 |
| [Spring] Singleton (0) | 2026.04.22 |