💡 Bean Scope
- 지금까지 한 실습에서 스프링 빈이 스프링 컨테이너의 시작과 함께 생성되어 스프링 컨테이너가 종료될 때까지,
유지한다고 학습했다. - 이것은 스프링 빈이 기본적으로 싱글톤 스코프로 생성이 되기 때문.
- 스코프는 번역 그대로 빈이 존재할 수 있는 범위를 뜻함
스프링의 싱글톤 스코프 지원 범위
- '싱글톤'
- 기본 스코프, 스프링 컨테이너의 시작과 종료까지 유지되는 가장 넓은 범위의 스코프
- '프로토타입'
- 스프링 컨테이너는 프로토타입 빈의 생성과 의존관계 주입까지만 관여하는 매우 짧은 범위의 스코프
- '웹 관련 스코프'
- 'request' = 웹 하나 요청이 들어오고 나갈때 까지(각각의 요청 따로) 유지되는 스코프
- 'session' = 웹 세션이 생성되고 종료될때 까지 유지되는 스코프
- 'application' = 웹의 서블릿 컨텍스트와 같은 범위로 유지되는 스코프
빈 스코프 지정
- 자동 등록 / 수동 등록
- 자동 등록 = @Component 어노테이션이 붙은 클래스에 @Scope("TYPE")을 지정하면 됨
- 수동 등록 = 수동 등록한 @Bean 메소드에 @Scope("TYPE")을 지정하면 됨
프로토타입 스코프
- 싱글톤 스코프의 빈을 조회하면 스프링 컨테이너는 항상 같은 인스턴스의 스프링 빈 반환.
- 프로토타입 스코프를 조회하면 항상 새로운 인스턴스를 생성해서 반환
- 예시)
1. 프로토타입 스코프의 빈을 스프링 컨테이너에 요청
2. 컨테이너는 이 시점에 프로토타입 빈을 생성하고, 필요한 의존관계 주입
3. 컨테이너는 생성한 프로토타입 빈을 클라이언트에 반환
4. 이후 컨테이너에 같은 요청이 오면 항상 새로운 프로토타입 빈 생성 후 반환 - 핵심* 컨테이너는 프로토타입 빈 생성, 의존관계 주입, 초기화까지만 처리하고 클라이언트에 빈 반환 후,
컨테이너는 더이상 프로토타입 빈을 관리하지 않는다. 이후 빈의 관리책임은 빈을 받은 클라이언트로 위임된다.
종료 메소드도 클라이언트에서 호출 해줘야함 - 코드로 보는 예시)
- 아래 코드에서 프로토타입 빈은 생성(각각 다른 인스턴스),init, 의존성 주입까지만 됨
- 스프링 컨테이너에서는 의존성 주입까지만 관리되기 때문에 종료 메소드인 destroy()가 실행이 안됨
- 수동으로 종료하려면 빈.destroy(); 를 직접 ac.close() 위에 적어주자
싱글톤 빈 내부에서 프로토타입 빈 사용시 문제점
- 예시) 싱글톤 빈이 의존관계 자동 주입을 통해 프로토타입 빈을 주입받는 상황 가정
클라이언트가 원하는것 = 프로토타입 빈을 호출할때마다 새로운 인스턴스 반환
- 프로토타입 빈 (addCount() 메소드 보유)
1. 싱글톤 빈 -> 스프링 컨테이너에 프로토타입 빈 요청
2. 컨테이너가 빈을 생성해서 싱글톤 빈에 반환, 프로토타입 빈의 count 필드값은 0
3. 싱글톤 빈 내부에 프로토타입 빈 보관(참조값 보관)
4. 클라이언트A 에서 싱글톤 빈의 로직 호출
5. 받은 빈의 로직 내부에 프로토타입 빈의 addCount() 메소드 실행으로 인해 count = 1 이되고 반환
6. 클라이언트B 에서 싱글톤 빈의 로직 또 호출
7. 기존 싱글톤 내부에 있던 프로토타입의 count가 1->2가 되서 2를 반환 받음
즉, 싱글톤 빈은 생성 시점에만 의존관계를 주입받기 때문에 내부의 프로토타입도 같이 유지된다.
싱글톤 빈 내부에서 프로토타입 빈 사용시 해결방법
ObjectProvider 사용
ObjectProvider = 지정한 빈을 찾아주는 DL 서비스 제공. 별도의 라이브러리 없음, 스프링에 의존적
- 가장 간단한 방법은 싱글톤이 프로토타입을 사용할 때마다 스프링 컨테이너에 새로 요청
- ApplicationContext ac; 를 @Autowired로 주입받아서 사용
- 이렇게 외부주입이 아닌 직접 의존관계를 찾는것을 Dependency Lookup = DL이라고 함
- ↑ 하지만 이렇게 하면 스프링 컨테이너에 종속적인 코드가 되고, 단위테스트도 힘들어진다.
- 지금 필요한 기능은 지정한 프로토타입 빈을 컨테이너에서 대신 찾아주는 DL 정도의 기능만 제공하는 무언가만 있으면 됨.
스프링에 의존적이지 않은 JSR-330 Provider 사용
- 자바 표준이므로 다른 컨테이너에서도 사용 가능
- 이 방법을 사용하려면 라이브러리를 bulid.gradle에 추가해야함
- implementation 'javax.inject:javax.inject:1'
💡 Request Scope 만들기
어플리케이션 실행 시 오류, Why?
실행 시점에 싱글톤 빈은 생성해서 주입이 가능하지만, request 스코프 빈은 아직 생성되지 않는다.
이 빈은 실제 클라이언트의 요청이 와야 생성할 수 있다.
그렇게 되려면 스프링 컨테이너한테 이 request빈을 요청 단계를 의존관계 주입 전으로 미뤄야 한다
이걸 해결하려면 아까 배운 ObjectProvider를 사용해서 코드 수정을 해보자
'Inflearn 강의 > Spring 핵심원리 기본' 카테고리의 다른 글
9 - Bean 초기화, 소멸 메소드 (0) | 2022.10.22 |
---|---|
8 - 의존관계 자동 주입 & 옵션 처리 (0) | 2022.10.18 |
7 - Component Scan (0) | 2022.10.18 |
6 - @Confituration과 Singleton / 바이트코드 조작 (0) | 2022.10.17 |
5 - Singleton Container with Stateless (0) | 2022.10.17 |