Spring 9. 빈 스코프
9. 빈 스코프

빈 스코프

  • 싱글톤: 기본 스코프, 스프링 컨테이너의 시작과 종료까지 유지
  • 프로토타입: 빈의 생성과 의존관계 주입까지만 관여하고 관리안함. 필요할때마다 매번 생성 (싱글톤과 반대), destroy도 책임 안짐
  • 웹 관련 스코프
    • request: 웹 요청이 들어오고 나갈때까지 유지
    • session: 웹 세션이 생성되고 종료될때까지 유지 (여러 request에 유지)
    • application: 웹의 서블릿 컨텍스와 같은 범위
    • websocket: 웹소켓과 동일한 같은 범위

사용법 @Scope

@Scope("prototype")
@Component
public class HelloBean {}
  • class 또는 메소드 위에 @Scope를 달아서 지정하면된다.

싱글톤 타입과 프로토타입이 같이 사용될때 문제가 생긴다.

  • 싱글톤에서 프로토타입 주입시 싱글톤은 처음에 주입받은 프로토타입을 계속 사용하기때문에 새로 초기화가 안된다.
  • 프로토타입 설계 자체를 사용할때마다 초기화 한걸 기대했으면 오류가 날 수 도있다.
    • 극단적인 해결방법 중 하나는 applicationContext를 받아와서 매번 사용할때마다 context에서 꺼내오면된다.
  • Provider를 사용해서 해결할 수 있다!
    • Dependency Lookup 의존관계를 자동으로 주입이아니라, 필요한것을 찾아 사용하는 것.

ObjectFactory, ObjectProvider

  • ObjectProvider, ObjectFactory 사용법. 대신 context에서 찾아서 생성해준다.
@RequiredArgsConstructor
static class ClientBean {
    private final ObjectProvider<PrototypeBean> prototypeBeanObjectProvider;
    // private final ObjectFactory<PrototypeBean> prototypeBeanObjectProvider;


    public int logic() {
        PrototypeBean prototypeBean = prototypeBeanObjectProvider.getObject();
        prototypeBean.addCount();
        return prototypeBean.getCount();
    }
}
  • ObjectProvider, ObjectFactory 둘다 똑같이 사용 가능
    • ObjectProvider가 ObjectFactory를 상속받았고, 추가 편의 기능들도 제공
  • 내부에서 스프링 컨테이너에서 해당 빈을 그때그때 찾아 반환
  • 스프링에 의존적

JSR-330 Provider (자바 표준으로 정의된 Provider)

  • build.gradle에 추가해줘야한다. `implementation ‘javax.inject:javax.inject:1’
import javax.inject.Provider; // * 꼭 javax.inject 라이브러리 사용해야한다.

@RequiredArgsConstructor
static class ClientBean {
    private final Provider<PrototypeBean> prototypeBeanObjectProvider;

    public int logic() {
        PrototypeBean prototypeBean = prototypeBeanObjectProvider.get();
        prototypeBean.addCount();
        return prototypeBean.getCount();
    }
}
  • 별도의 라이브러리가 필요하다.
  • 자바 표준 라이브러리서 다른 컨테이너에서도 사용가능.
  • DL은 순환참조에 사용 가능

근데 그러면 spring이 만든 ObjectProvider랑 자바 표준 Provider 중에는 뭘 사용해야되지??

  • 스프링은 대세가 스프링에서만든 코드 사용하는것… ㅋㅋㅋㅋ 자바 표준이 아직 기능이 너무 불편해서 사람들이 사용을 잘않나다.

request scope 빈을 사용해보자!

@Component
@Scope(value = "request")
public class MyLogger { ... }
-----
  
@Service
@RequiredArgsConstructor
public class LogDemoService {
    private final ObjectProvider<MyLogger> myLoggerProvider;
    private final MyLogger myLogger;

    public void logic(String id) {
//        MyLogger myLogger = myLoggerProvider.getObject();
        myLogger.log("service id = " + id);
    }
}
  • MyLogger를 생성자 주입통해서 받을라면 현재 스코프에 생성된 빈이 없다고 실행자체가 안된다.
    request 주입 오류

  • 해결 방법으로는 ObjectProvider를 통해 사용하는 쪽에서 매번 getObject를 해서 사용해야한다.

Provider 보다 더 좋은 방법이 있었다! proxyMode를 사용하자!

@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyLogger { ... }
  • proxyMode를 ScopedProxyMode.TARGET_CLASS로 설정해두면, 프록시 패턴을 통해 CGLIB 라이브러리를 통해 바이트 코드를 조작해서 원래 객체, 수정된 프록시 객체를 생성한다.
    • 객체를 사용하는 곳에서 context에 지연 조회를 한다.

싱글톤 외의 특별한 스코프들은 꼭 필요한곳에서만 사용하자! 유지보수가 어렵다

© 2025 seokh1213

LinkedIn LinkedIn GitHub