[SPRING] Bean Scope

2023. 3. 5. 21:00

✔Bean scope란?

Bean scope란 bean이 존재할수 있는 범위를 의미한다.

 

스프링이 지원하는 Scope 종류 (그대로 복붙임 수정해)

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

 

 

 

 

 

 

✔Prototype Scope

싱글톤 스코프에서 bean조회시 스프링 컨테이너는 항상 같은 인스턴스의 스프링 bean을 반환했지만

prototype scope 를 스프링컨테이너에서 조회한다면 항상 새로운 인스턴스를 반환한다.

  • 즉 스프링 컨테이너는 프로토타입 bean을 생성하고, 의존관계 주입, 초기화까지 처리한후 더이상 생성된 prototype bean을 관리하지 않는다.

❗❗ 스프링 컨테이너가 bean의 생성이후 관리를 하지 않기 떄문에 @PreDestroy 같은 종료 메서드는 호출되지 않는다. 따라서 프로토타입 빈은 프로토타입 빈을 조회한 클라이언트가 관리해야 한다. 종료 메서드에 대한 호출도 클라이언트가 직접 해야한다.

 

 

 

 

 

 

✔싱글톤에서 프로토타입 빈을 사용

 

beanscope1

위사진과같이 Singleton인 clientBean에 Prototype인 bean이 있다고가정한다.

이때 클라이언스 A가 특정 logic을 통해 prototype bean에 존재하는 count의 값을 1증가시킨다 가정하자.

그후 새로운 클라이언트 B가 prototype bean에 존재하는 count의 값을 1증가시킨다 가정한다.

이때 clientBean은 Singleton이다 따라서 클라이언트A 와 클라이언트B는 서로같은 clientBean에 접근하는데

클라이언트A 와 클라이언트B가 접근하는 prototype bean또한 같은 bean이다.

따라서 각 클라이언트가 count를 1씩 증가시킨다하면 count는 2가 된다.

근데 이렇게 된다면 사실 prototype bean을 사용하는 이유가 없다, 우리가 원하는 방향은 각각의 클라이언트가 특정 logic(count++)을 실행할때마다 새로운 프로토타입 bean을 만들어 logic을 적용하고싶은 의도와 달라지기 때문이다.(즉 count가 2 가되는게 아닌 각각의 count가 1 이 되도록) 이러한 문제를 해결하는 방법을 소개한다.

 

 

 

  1. 싱글톤 빈이 프로토타입을 사용할 때 마다 스프링 컨테이너에 새로 요청하는 것이다.
	public int logic() {
	    PrototypeBean prototypeBean = ac.getBean(PrototypeBean.class);
	    prototypeBean.addCount();
	    int count = prototypeBean.getCount();
	    return count;
	}

위 코드처럼 특정 logic을 사용할때마다 PrototypeBean을 스프링 컨테이너에 요청한다. (Dependency Lookup DL)

 

 

  1. ObjectFactory, ObjectProvider
   @Autowired
   private ObjectProvider<PrototypeBean> prototypeBeanProvider;
       public int logic() {
           PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
           prototypeBean.addCount();
           int count = prototypeBean.getCount();
           return count;
}

위 코드에서 우리가 원하는 의도인 항상 새로운 prototype bean이 생성되는것을 알수있다.

ObjectProvider DL 정도의 기능만 제공한다.

 

 

  1. JSR-330 Provider
   @Autowired
   private Provider<PrototypeBean> provider;
       public int logic() {
           PrototypeBean prototypeBean = provider.get();
           prototypeBean.addCount();
           int count = prototypeBean.getCount();
           return count;
       }

JSR-330 Provider 를 사용하려면 따로 library를 추가해줘야한다.

JSR-330 Provider는 자바 표준이라 ObjectProvider 처럼 Spring에 의존적이지 않지만 ObjectProvider와 마찬가지로 DL 정도의 기능만을 제공한다.

 

 

 

 

 

 

✔웹스코프

웹스토프는 웹환경에서 동작을 하며, 프로토타입 스코프와는 다르게 스프링이 해당 스코프의 종료 시점까지 관리를 한다.

 

web scope 종류

  • request: HTTP 요청 하나가 들어오고 나갈 때 까지 유지되는 스코프, 각각의 HTTP 요청마다 별도의 빈 인스턴스가 생성되고, 관리된다.
  • session: HTTP Session과 동일한 생명주기를 가지는 스코프
  • application: 서블릿 컨텍스트( ServletContext )와 동일한 생명주기를 가지는 스코프
  • websocket: 웹 소켓과 동일한 생명주기를 가지는 스코프

beanscope2

 

@Scope(value = "request") 를 사용할때 만약 우리가 스프링 컨테이너 생성 시점에 request Scope bean을 가져와야한다면, 이때 오류가 발생할수 있다. 그이유는 request Scope bean은 스프링 컨테이너 생성시점이 아닌 고객의 요청이 들어온 이후에 생성이 되기 때문이다. 따라서 이러한 오류를 발생시키지 않기위한 방법을 소개한다.

 

 

  1. Provider 사용
   private final ObjectProvider<MyLogger> myLoggerProvider;
   
   @RequestMapping("log-demo")
   @ResponseBody
   public String logDemo(HttpServletRequest request) {
   	String requestURL = request.getRequestURL().toString();
   	MyLogger myLogger = myLoggerProvider.getObject();
       ...
   }

provider를 통해 bean이 주입 시점이 아니라 실제로 필요할 때 생성되게 할수있다. 따라서 사용자의 요청이 왔을때 bean을 생성하여 원하는 처리를 할수 있게 된다.

 

 

  1. proxyMode 사용
   // @Scope(value = "request") //이전코드
   @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)

위와같이 proxyMode 를 사용하면 (provider는 사용안함) HTTP request와 상관 없이 가짜 프록시 클래스를 다른 빈에 미리 주입해 , 스프링 컨테이너 생성 시점에 request Scope bean을 가져와 발생하는 오류를 해결할수 있다. (간단히 말해 가짜 객체를 만들고 추후 client의 request가 들어올때 진짜 객체를 찾아와 필요한 처리를 해준다)

 

 

  • 결론 : 사실 Provider를 사용하든, 프록시를 사용하든 핵심 아이디어는 진짜 객체 조회를 꼭 필요한 시점까지 지연처리 한다는 점이다.

 

🙏Reference

'Spring' 카테고리의 다른 글

[SpringMVC] DTO 사용이유  (0) 2023.04.09
[SpringMVC] addViewController사용할때 주의할점  (0) 2023.04.09
[SPRING] Bean Life cycle, call back  (0) 2023.03.05
[SPRING] 의존관계 자동 주입  (1) 2023.03.05
[SPRING] Component scan  (0) 2023.03.03

+ Recent posts