ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring bean 정리(3)_Spring Bean 스코프
    Spring Framework 2023. 8. 13. 15:49

    bean scope

    • 빈이 존재할 수 있는 범위

     

    Singleton scope

    • 기본 스코프, 스프링 컨테이너의 시작과 종료까지 유지되는 가장 넓은 범위의 스코프
    • Singleton bean은 컨테이너 생성 시점에 같이 생성되고 초기화된다.
    • 생성된 하나의 인스턴스는 Spring Beans Cache에 저장되고, 해당 빈에 대한 요청과 참조가 있으며 캐시된 객체를 반환한다. 하나만 생성되기 때문에 동일 참조를 보장한다.
    • 모든 빈은 스코프가 명시적으로 지정되지 않으면 싱글톤이다.
    • 대상 클래스에 @Scope(”singletone”) 을 붙이면 된다.
    • 각각 다른 요청에서 boardService bean(Singleton scope의 bean)을 요청하면 스프링 컨테이너는 동일한 boardService bean을 반환한다.

     

    Prototype scope

    • 짧은 범위의 스코프
    • Prototype bean을 요청하면 스프링 컨테이너는 항상 새로운 Prototype bean을 생성하고 필요한 의존관계를 주입해 반환한다.
    • Prototype bean이 생성된 이후에는 스프링 컨테이너에서 관리하지 않아, 관리에 대한 책임이 클라이언트에게 있다.
    • Prototype bean은 스프링 컨테이너에서 빈을 조회할 때 생성되고 초기화 메서드도 실행된다.
    • 대상 클래스에 Scope("prototype") 을 붙이면 된다.

     

    * 싱글톤 객체가 프로토 타입 객체를 가지고 있는 경우 생기는 문제점

    • 싱글톤 빈으로 생성되는 시점에 프로토 타입 빈이 생성되어 들어오기 때문에 싱글톤 빈 내부의 프로토 타입 빈을 호출하게 되면 매번 같은 값을 가져 온다.
    • 해결방법
      • Provider
      • @Scope의 proxyMode 설정

    Provider

    - logic() 메소드를 호출할 때마다 다른 PrototypeBean 인스턴스가 호출된다. Provider는 자바 표준이라서 스프링에 독립적이라는 장점이 있다.

    @Component
    class ClientBean {
        @Autowired
        private Provider<PrototypeBean> provider;    //javax.inject 하위 클래스로 import해야함
    
        public int logic() {
            PrototypeBean prototypeBean = provider.get();    // 컨테이너에 빈 요청
            prototypeBean.addCount();
            return prototypeBean.getCount();
        }
    }

    @Scope의 proxyMode 설정

    - 해당 객체에 @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_ClASS) 설정

    - 적용대상이 클래스면 TARGET_CLASS를 선택, 적용대상이 인터페이스면 INTERFACES를 선택

     

     

    웹 관련 scope

    • 스프링이 해당 스코프의 종료 시점까지 관리한다. 따라서 종료 메서드가 호출된다.
    • 스프링 빈 등록 시 웹 스코프를 그대로 주입받으면 오류가 발생한다.
    • request 스코프의 경우 HTTP 요청이 올 때 새로 생성되고 응답하면 사라지기 때문에, 싱글톤 빈이 생성되는 시점에는 아직 생성되지 않음  (의존관계 주입이 불가능하다.)

    * 의존 관계 주입 불가능을 해결하는 방법 = @Scope의 proxyMode 설정

    @Component
    @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_ClASS)
    public class MyLogger {
    	/*
    	적용대상이 클래스면 TARGET_CLASS를 선택
    	적용대상이 인터페이스면 INTERFACES를 선택
    	*/
    	// code...
    }
    • MyLogger의 가짜 프록시 클래스를 만들어두고 HTTP request와 상관없이 가짜 프록시 클래스를 다른 빈에 미리 주입해둘 수 있다.
      1. 스프링 컨테이너는 CGLIB라는 바이트코드 조작 라이브러리를 사용해서, 해당 웹 스코프 빈 클래스를 상속하는 가짜 프록시 객체를 생성한다.
      2. 가짜 프록시 객체는 요청이 오면 그때 내부에서 진짜 빈을 요청하는 위임 로직이 들어있다.
      3. 가짜 프록시 객체는 내부에 진짜 myLogger를 찾는 방법을 알고 있어, 클라이언트가 myLogger.logic()을 호출하면 사실은 가짜 프록시 객체의 메서드를 호출한다.
      4. 가짜 프록시 객체는 request 스코프의 진짜 myLogger.logic()을 호출한다.
      5. 가짜 프록시 객체는 원본 클래스를 상속받아서 만들어졌기 때문에 이 객체를 사용하는 클라이언트 입장에서는 원본인지 아닌지도 모르게 동일하게 사용할 수 있다(다형성)
    • 웹 scope 종류
      • request : HTTP 요청 하나가 들어오고 나갈 때까지 유지되는 스코프, 각각의 HTTP 요청마다 별도의 빈 인스턴스가 생성되고 관리된다.
      • session : HTTP Session과 동일한 생명주기를 가지는 스코프
      • application : 서블릿 컨텍스트(ServletContext)와 동일한 생명주기를 가지는 스코프
      • websocket : 웹 소켓과 동일한 생명주기를 가지는 스코프

     

     

    출처)

    https://steady-coding.tistory.com/594
    https://code-lab1.tistory.com/186

Designed by Tistory.