ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring][Kotlin] 빈 스코프
    Spring 2022. 5. 21. 15:44

    빈 스코프란?

    빈 스코프는 빈이 존재할 수 있는 범위를 뜻한다.

     

    스프링은 다양한 스코프를 지원한다.

    • 싱글톤 : 기본 스코프. 스프링 컨테이너의 시작과 종료까지 유지되는 가장 넓은 범위의 스코프
    • 프로토타입 : 스프링 컨테이너는 프로토타입 빈의 생성과 의존관계 주입까지만 관여하고 더는 관리하지 않는 매우 짧은 범위의 스코프
    • 웹 스코프
      • request : 웹 요청이 들어오고 나갈때 까지 유지되는 스코프
      • session : 웹 세션이 생성되고 종료될 때 까지 유지되는 스코프
      • application : 웹의 서블릿 컨텍스트와 같은 범위로 유지되는 스코프

     

    빈 스코프는 다음과 같이 지정 가능하다

    [컴포넌트 스캔 자동 등록]

    @Scope("prototype")
    @Component
    class HelloBean{...}

    [수동 등록]

    class LifeCycleConfig{
    	@Scope("prototype")
    	@Bean
    	fun helloBean = HelloBean()
    }

     

     

     

    프로토타입 스코프

    싱글톤 스코프의 빈을 조회하면 스프링 컨테이너는 항상 같은 인스턴스의 스프링 빈을 반환한다.

    프로토타입 스코프의 빈을 조회하면 스프링 컨테이너는 항상 새로운 인스턴스를 생성해서 반환한다.

    그리고 스프링 컨테이너는 생성한 프로토타입 빈을 클라이언트에게 반환한다.

    이후에 같은 요청이 오면 새로운 프로토타입 빈을 생성해서 반환한다.

     

    생성한 객체를 클라이언트에게 반환하고 더이상 관리하지 않기 때문에 이때부터 클라이언트가 빈을 관리해야한다.

    -> @PreDestroy가 자동으로 호출되자 않는다.

     

     

    프로토타입 빈과 싱글톤 빈 함께 사용 시 문제점

    싱글톤 빈과 프로토타입 스코프의 빈을 함께 사용하면 잘 동작하지 않을 때가 있다.

     

    아래에서 싱글톤 빈이 의존관계 주입을 통해 프로토타입 빈을 주입받아서 사용하는 예를 보자

    clientBean은 싱글톤이므로 스프링 컨테이너 생성 시점에 함께 생성되고 의존관계 주입도 발생한다.

    clientBean이 의존관계 자동 주입을 사용한다면 주입 시점에 스프링 컨테이너에 프로토타입 빈을 요청한다.

    스프링 컨테이너는 프로토타입 빈을 생성해서 clientBean에 반환한다.

    clientBean은 프로토타입 빈의 참조값을 내부 필드에 보관한다.

     

    클라이언트가 싱글톤 빈인 clientBean을 스프링 컨테이너에게 요청해서 받고 그 내부의 프로토타입 빈을 이용해서 로직을 수행하는 상황이 있다.

    클라이언트가 프로토타입 빈을 몇 번을 요청해도 이 프로토타입 빈은 모두 같은 객체이다(싱글톤 빈 내부의 저장된 참조값을 참고해 반환해주기 때문이다.)

    따라서 새로운 객체라고 생각하고 사용하면 의도치 않는 동작이 일어난다.

     

    프로토타입 스코프 : 싱글톤 빈과 함께 사용 시 Provider로 문제 해결

    지금 필요한 기능은 지정한 프로토타입 빈을 컨테이너에서 찾아주는 DL기능이다.

    DL : Dependency Lookup = 의존관계 탐색

    스프링에는 이런 기능을 제공하는 것이 있다.

     

    ObjectFactory, ObjectProvider

    [ObjectProvider]

    : getObject하면 그때서야 스프링 컨테이너에게 오브젝트 받아서 반환해주는 기능 제공(DL)

     

    [ObjectFactory]

     : getObject 기능 하나만 제공

     

    ObjectProvider는 ObjectFactory 인터페이스를 상속받고 있다.

    옵션, 스트림 처리 등 편의 기능이 많다.

    별도의 라이브러리는 필요 없지만 스프링에 의존한다.

     

    정리

    사실 싱글톤 빈으로 대부분의 문제를 해결할 수 있다.

    프로토타입 빈은 매번 사용할 때 마다 의존관계 주입이 완료된 새로운 객체 필요할 때 사용하면 된다.

     

    스프링이 제공하는 기능와 자바 표준이 둘다 비슷한 기능을 제공한다면 다양하고 편리한 기능을 제공해주는 스프링을 쓰자.
    다른 컨테이너를 쓸 일이 있다면 자바 표준을 쓰면 된다.

     

    웹 스코프

    웹 스코프는 웹 환경에서만 동작한다.

    프로토타입 스코프와 다르게 스프링이 스코프의 종료시점까지 관리한다. -> 종료 메서드가 호출됨

     

    request

    HTTP 요청 하나가 들어오고 나갈 때 까지 유지되는 스코프.

    각각의 HTTP 요청마다 별도의 빈 인스턴스가 생성되고 관리된다.

    session

    HTTP Session과 동일한 생명주기를 가지는 스코프

    application

    서블릿 컨텍스트(Servlet Context)와 동일한 생명주기를 가지는 스코프

    websocket

    웹 소켓과 동일한 생명주기를 가지는  스코프

     

    P] 스프링 앱 실행 시점에 싱글톤 빈 생성해서 주입 가능하지만 request 빈은 실제 고객의 요청이 와야 생성이 가능하기 때문에 오류가 발생할 수 있다.

     

    스코프와 Provider

    Provider을 적용한다면 ObjectProvider.getObject()를 호출하는 시점까지 request scope 빈의 생성을 지연할 수 있다.

     

    스코프와 프록시

    프록시의 방법을 사용해 문제를 해결해보자.

    @Component
    @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
    class xxx{...}
    적용 대상이 클래스면 TARGET_CLASS, 
    적용 대상이 인터페이스이면 INTERFACES를 선택

     

    이렇게 프록시 방식을 사용하기만 하면 오류가 발생하지 않는다.

    이유를 알아보자.

     

    주입된 스코프 빈의 클래스 정보를 찍어보면 CGLIB 라이브러리로 만든 객체라는 것을 알 수 있다.

    //클래스 정보 출력 결과
    xxx = class soyang.hellocore.common.xxx$$EnhancerBySpringCGLIB&&~~~

     

    @Scope의 proxyMode = ScopedProxyMode.TARGET_CLASS 를 설정하면 스프링 컨테이너는 CGLIB라는 바이트코드를 조작하는 라이브러리를 사용해서 xxx를 상속받은 가짜 프록시 객체를 생성한다.

    그리고 스프링 컨테이너에 빈 이름으로 진짜 대신 가짜 프록시 객체를 등록한다.

    (xxx 타입의 자식 타입이기 때문에 빈 조회시 조회 가능하다)

    의존관계 주입도 이 가짜 프록시 객체가 주입된다.

     

    가짜 프록시 객체는 요청이 오면 그때 내부에서 진짜 빈을 요청하는 위임 로직이 들어있다.

    (내부에 진짜 객체를 찾는 방법을 알고 있다.

    클라이언트가 객체의 메서드를 호출하면 (이 객체는 프록시 객체이므로) 가짜 프록시 객체의 메서드가 호출되지만 이 가짜 프록시 객체가 request 스코프의 진짜 객체의 메서드를 호출한다.

     

    클라이언트 입장에서는 원본인지 아닌지 모르게 동일하게 사용할 수 있다(다형성)

     

     

    [출처]

    스프링 핵심 원리 - 기본편

    https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard

     

    스프링 핵심 원리 - 기본편 - 인프런 | 강의

    스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., - 강의 소개 | 인프런...

    www.inflearn.com

     

Designed by Tistory.