공부/spring

[Spring] Bean Scope

bitamango 2026. 4. 25. 16:57

빈 스코프 : 빈이 존재할 수 있는 범위

 

- 싱글톤 : 기본 스코프. 스프링 컨테이너의 시작 ~ 종료까지 유지되는 가장 넓은 범위의 스코프

    - 빈 조회 시 스프링 컨테이너는 항상 같은 인스턴스의 스프링 빈 반환

 

- 프로토타입 : 빈 생성 ~ 의존관게 주입까지만 관여. 매우 짧은 스코프

    - 빈 조회 시 스프링 컨테이너는 항상 새로운 인스턴스를 생성해서 반환

    - 프로토타입 빈을 관리할 책임 --> 프로토타입 빈을 받은 클라이언트에 있다

    - @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