본문 바로가기
Spring | SpringBoot

[스프링 스터디] 7주차 - 스프링 핵심 원리.기본편 (마지막)

by saniii 2022. 2. 24.

긴 듯, 짧은 듯 스프링 스터디의 마지막 주차...!   

 

공부한 github : https://github.com/anso33/SpringStudy_second.git


[ 섹션 9. 빈 스코프 ]

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

 

스프링은 싱글톤과 프로트타입 등 다양한 스코프를 지원한다. 

ex)

  • 싱글톤 
  • 프로토타입
  • 웹 관련
    • request
    • session
    • application

 

-  @Component를 이용해서 자동으로 등록할 수도 있고, 수동으로 등록할 수도 있다. 

 

 

# 프로토타입 스코프

 

프로토타입 스코프의 빈을 요청하면 스프링 컨테이너가 프로토타입 빈을 생성하고 의존관계를 주입하여 반환한다.

싱글톤과 다르게 요청을 받을 때마다 새로운 프로토타입 빈을 생성하여 반환한다. 

 

스프링 컨테이너는 프로토타입 빈에 대해 생성, 의존관계 주입, 초기화까지만 담당한다. 

따라서 이후 관리는 해당 프로토타입 빈을 반환받은 클라이언트가 해야한다. 

 

여기서의 결과와 같이 싱클톤 스코프의 빈을 요청하면 같은 객체를 계속해서 반환한다. 

 

 

반면

 

프로토타입 스코프의 빈은 요청 시마다 다른 객체가 반환되고 있음을 확인할 수 있다. 

또한 스프링 컨테이너가 종료까지 관리하지 않기 때문에 @PreDestroy(종료 메서드)가 실행되지 않는다.

 

 

프로토타입 빈의 특징 정리

  • 스프링 컨테이너에 요청할 때 마다 새로 생성된다.
  • 스프링 컨테이너는 프로토타입 빈의 생성과 의존관계 주입 그리고 초기화까지만 관여한다.
  • 종료 메서드가 호출되지 않는다.
  • 프로토타입 빈은 프로토타입 빈을 조회한 클라이언트가 관리해야 한다. 종료 메서드에 대한 호출도 클라이언트가 직접 해야한다.

보통은 거의 싱글톤을 사용한다. 

 

 

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

 

싱글톤 빈(이름을 클라이언트빈이라고 하자)에서 프로토타입 빈을 요청하여 사용할 때 컨테이너에 요청하여 반환받은 프로토타입 빈을 클라이언트빈 내부 필드에 보관하게된다. 이때 클라이언트 빈은 새로 요청하지 않는 이상 컨테이너로 부터 받은 프로토타입 빈을 계속해서 재사용하게 된다.

사용자가 여러명 있을 때 클라이언트 빈은 싱글톤 빈이므로 모든 사용자가 같은 객체의 클라이언트빈을 사용하게된다. 이때 프로토타입빈은 싱글톤 빈이 아니기때문에 개인의 필드값을 저장할 수 있다. 즉, 사용자1이 클라이언트 빈을 사용하여 프로토타입 빈의 필드값이 생기고 나면 사용자2가 같은 클라이언트 빈을 사용하게 될 때 깨끗한 프로토타입빈을 사용하게 되는 것이 아닌 오염된 프로토타입빈을 사용하게 되는 것이다. >> 문제점

 

 

 

 

 

스프링은 일반적으로 싱글톤 빈을 사용하므로, 싱글톤 빈이 프로토타입 빈을 사용하게 된다. 그런데 싱글톤 빈은 생성 시점에만 의존관계 주입을 받기 때문에, 프로토타입 빈이 새로 생성되기는 하지만, 싱글톤 빈과 함께 계속 유지되는 것이 문제다.

 

 

더보기

 

위의 사진은 실패 케이스

 

 

이 오류를 고친게 아래 사진

 

 

 

 

 

 

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

 

싱글톤 빈과 프로토타입 빈을 함께 사용할 때, 항상 새로운 프로토타입 빈을 생성할 수 있는 방법

  • 프로토타입을 사용할 때마다 스프링 컨테이너에 새로 요청
  • 지정한 빈을 컨테이너에서 대신 찾아주는 DL서비스를 제공하는 ObjectProvider을 사용한다.
  • javax.inject.Provider라는 JSR-330 자바 표준을 사용한다. 

 

 

+ 프로토타입을 사용할 때마다 스프링 컨테이너에 새로 요청

 

의존관계를 외부에서 주입(DI) 받는게 아니라 이렇게 직접 필요한 의존관계를 찾는 것을 Dependency Lookup (DL) 의존관계 조회(탐색) 이라한다.

스프링의 애플리케이션 컨텍스트 전체를 주입받게 되면, 스프링 컨테이너에 종속적인 코드가 되고, 단위 테스트도 어려워진다.

지금 필요한 기능은 지정한 프로토타입 빈을 컨테이너에서 대신 찾아주는 딱! DL 정도의 기능만 제공하는 무언가가 있으면 된다.

 

 

+ 지정한 빈을 컨테이너에서 대신 찾아주는 DL서비스를 제공하는 ObjectProvider을 사용한다.

 

ObjectProvider getObject() 를 호출하면 내부에서는 스프링 컨테이너를 통해 해당 빈을 찾아서 반환한다. (DL)

DL 정도의 기능만 제공

별도의 라이브러리 필요 없음, 스프링에 의존

 

 

+ javax.inject.Provider라는 JSR-330 자바 표준을 사용한다. 

 

 

 

provider get() 을 호출하면 내부에서는 스프링 컨테이너를 통해 해당 빈을 찾아서 반환한다. (DL)

DL 정도의 기능만 제공

get() 메서드 하나로 기능이 매우 단순하다.

별도의 라이브러리가 필요하다

 

자바 표준이므로 스프링이 아닌 다른 컨테이너에서도 사용할 수 있다.

 

 

 

 

# 웹스코프

웹 스코프는 웹 환경에서만 동작한다.
웹 스코프는 프로토타입과 다르게 스프링이 해당 스코프의 종료시점까지 관리한다. 따라서 종료 메서드가 호출된다.

 

# request스코프 만들기 예제

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

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

 

이렇게 오류남 // 의존관계 주입 받고 있는데 스프링 컨테이너가 뜰때 컨트롤러를 스프링 빈에 등록하면서 의존관계를 주입해야한다. 이렇게 되면 컨테이너한테[ 마이로거를 내놓으라고 하는데 이 스코프가 리퀘스트 스콥, 근데 없다. (생존범위가 곡객(http-request)이 들어와서 나갈때까지인데 이 고객이 스프링을 띄우는 단계에서 나오지 않았다. 그래서 오류가 남.) 즉 스코프 리퀘스트가 활성화되지 않아서(클라이언트가 페이지를 요청하지 않아서) 오류가남

 

이때는 앞에서 배운 프로바이더를 사용하면 된다. 

 

 

# 스코프와 provider

 

 

ObjectProvider를 사용하여 스프링 컨테이너에 요청을 늦춰서 ObjectProvider.getObject() 를 호출하는 시점까지 request scope 빈의 생성을 지연할 수 있다.

- ObjectProvider.getObject() LogDemoController , LogDemoService 에서 각각 한번씩 따로 호출해도 같은 HTTP 요청이면 같은 스프링 빈이 반환.

 

 

 

 

프로바이더도 줄이고 싶다면..? >> 프록시

# 스코프와 프록시 

프록시 : 대리로 수행하는 것. 자신을 통해서 작업을 수행할 수 있게 하는 것

다른 코드는 고칠 것 없이 마이로그에 애노테이션 설정을 하는 것만으로도 같은 결과를 낼 수 있다. 

 

CGLIB라는 라이브러리로 내 클래스를 상속 받은 가짜 프록시 객체를 만들어서 주입한다. 이 가짜 프록시 객체는 실제 요청이 오면 그때 내부에서 실제 빈을 요청하는 위임 로직이 들어있다가짜 프록시 객체는 실제 request scope와는 관계가 없다. 그냥 가짜이고, 내부에 단순한 위임 로직만 있고, 싱글톤 처럼 동작한다

 

이런 특별한 scope는 꼭 필요한 곳에만 최소화해서 사용하자, 무분별하게 사용하면 유지보수하기 어려워진다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

댓글