0. 개요
- 이전 포스팅에서 Spring Bean의 생명주기에 대해 배웠다.
- Spring은 Spring Continer의 시작과 종료까지의 큰 흐름 안에 다양한 생명주기를 가진 Bean을 제공한다.
- 이번 포스팅에서는 다양한 Bean의 생명주기에 대해서 알아보자.
1. Bean Scope
a) Bean Scope란?
- Spring에는 다양한 종류의 Bean이 존재한다.
- Bean의 역할과 사용 목적에 따라 Bean의 종류가 달라지는데, 이에 따라 다양한 생명주기를 갖는다.
- Bean의 종류에 따라 달라지는 Bean 생명주기를 Bean Scope라고 부른다.
- 모든 Bean이 애플리케이션이 종료될 때까지 Spring Container에 의해 관리되는 것이 아니다.
- 즉, Scope는 Bean이 어느 시점까지 Spring Container에 의해 관리되는지를 정의한 것이다.
b) Bean Scope의 종류
- Spring은 다음과 같은 다양한 생명주기를 가진 Bean을 제공한다.
- Singleton Scope
- Prototype Scope
- Web Scope
2. Bean Scope의 종류와 특징
a) Singleton Scope
- 싱글톤은 Spring에서 기본적으로 Bean에게 부여하는 Scope다.
- Spring Container의 시작부터 종료까지 유지되는 가장 넓은 범위의 scope다.
- default로 제공되는 값이기 때문에, 따로 명시할 필요는 없으나, 다음과 같이 명시할 수 있다.
@Scope("sigleton")
- Singleton Scope를 가지는 Bean은 Spring Container가 종료될 때까지 Spring Container에 의해 관리된다.
- 그러므로 Client가 Bean을 요청할 때마다 동일한 Bean을 반환한다.
- 즉, 최초에 생성된 하나의 Bean을 계속해서 사용한다.
b) Prototype Scope
- 프로토타입은 Bean이 생성되고 DI가 주입된 후 Spring Container의 관리를 받지 않는다.
- 프로토타입은 매우 짧은 범위를 가지는 Bean scope다.
@Scope("prototype")
- 프로토타입 Scope를 가지는 Bean은 Spring Container에 의해 생성되고 반환된 후, Bean의 관리책임을 Client에게 양도한다.
- 그러므로 Client가 Bean을 요청할 때마다 새로운 Bean을 생성하여 반환한다.
- Bean 반환 후 Bean의 관리책임을 Client가 수행하므로, Client가 Bean 생명주기의 소멸 메서드를 호출해야 한다.
c) Web Scope
- 웹 작업을 처리하기 위해 사용하는 Bean에 부여되는 scope다.
- 웹 스코프는 다음과 같은 종류를 갖는다.
- Request Scope: HTTP Request가 처리될 때까지 유지된다.
- Session Scope: 웹 세션이 생성되고 종료될 때까지 유지된다. HTTP Session과 동일한 생명주기를 갖는다.
- Application Scope: 웹 서블릿 콘텍스트와 동일한 범위로 유지된다.
3. Singleton Bean과 Prototype Bean
- 서로 다른 Scope을 가진 Bean을 이용하여 의존관계를 형성하면 어떻게 될까?
- 아마도 서로 다른 생명주기로 인해 문제가 발생할 것이다.
- 어떤 문제인지, 그 해결책은 무엇인지 알아보자.
* 실무에서는 대부분 싱글톤 Bean을 사용하여 개발한다. 그러므로 프로토타입 Bean을 사용할 일은 매우 드물다.
a) 문제점 (SB = Singleton Bean, PB = Prototype Bean)
- 예를 들어, SB에서 PB을 주입받아 사용한다고 해보자.
- SB은 Spring Container가 종료되기까지 하나의 객체를 계속해서 사용한다.
- 즉, 주입받은 PB를 계속해서 사용하게 된다.
- PB는 요청될 때마다 Spring Container가 새로운 PB를 생성한다.
- 그러나 SB와 함께 사용하면 PB의 특성을 사용하지 못하게 된다.
b) 해결책 - Dependency Lookup
- 이 문제의 해결방안은 SB 내부에서 Spring Container에게 PB를 달라고 요청하는 것이다.
- 즉, DI를 주입받는 것이 아니라 필요한 DI 대상을 직접 요청하는 DL을 수행하는 것이다.
- 그러나 여기에는 한 가지 문제점이 있다. 바로 SRP를 위배한다는 것이다.
- 더불어, SB에서 Spring Container에게 PB를 요청하므로 코드 자체가 Spring Container에게 의존적이다.
- 그렇다면 이 과정(DL)을 외부에서 누군가 대신해주면 되지 않을까?
4. Dependency Lookup
a) Object Factory, Object Provider
- Object Factory와 Object Provider 모두 DL을 수행하는 역할을 가진 인터페이스다.
- Object Provider는 Object Factory를 상속받은 인터페이스로, 더 많은 기능을 가진다.
- 핵심은 DL을 외부에서 대신 수행할 수 있다는 것이다.
- 그러나 이는 Spring에서 제공하는 기능으로, Spring에 종속적인 코드라는 점은 동일하다.
b) JSR-330 Provider
- JSR(Java Specification Request)은 Java 표준을 의미한다.
- JSR에서도 Provider 라이브러리를 제공하며, Gradle에 추가하여 사용할 수 있다.
- JSR에서 제공하는 Provider에는 get() 메서드 하나만 존재하며, DL 기능을 수행한다.
- Java 표준이므로 Spring에 종속적이라는 문제점을 해결한다.
package javax.inject;
public interface Provider<T> {
T get();
}
5. Web Scope
- 웹 scope는 웹 환경에서만 동작한다.
- 웹 scope는 스프링이 해당 scope의 종료 시점까지 관리한다.
a) Web Scope와 DL
- web scope는 왜 DL 기능을 필요로 할까?
- HTTP Request를 Bean으로 사용하는 코드를 작성한 경우, 빌드 시점에서 오류가 발생한다.
- 그 이유는 아직 HTTP Request가 서버에 들어오지 않아 Request 객체가 존재하지 않으나,
Request 객체를 사용하여 의존 관계를 형성하기 때문이다.
- 그렇다면 인위적으로 외부에서 Request 객체를 만들어 주입해주면 되지 않을까?
- Request가 사용하는 DL 기능을 알아보자.
b) @Scope 옵션 - Proxy
- @Scope에는 proxyMode라는 옵션이 있다.
@Scope(value = "request", proxyMode = ScopeProxyMode.TARGET_CLASS)
// scope // 적용 대상의 타입을 명시
- 이는 가짜 request 객체를 만들어 주입시켜주는 방식으로,
Spring이 최초 빌드 시점에서 의존관계 형성에 필요한 request 객체를 대신하기 위함이다.
→ 실제로 최초에 생성되는 가짜 request 객체는 CGLIB에 의하여 복사된 객체다.
- 빌드 시점에서는 가짜 request 객체를 사용하지만, 실제로 HTTP 요청이 들어오면 실제 Request 객체가 생성 및 사용된다.
→ 이를 Spring의 위임 기능이라고 한다.
- Spring 위임 기능이라 하면 Spring Bean 자체가 가짜에서 진짜로 변경된다고 생각할 수 있다.
→ 실제로는 request의 생명주기 동안 가짜 객체가 계속 사용되는데, 가짜 객체는 진짜 객체에 접근할 수 있다.
→ 가짜 객체가 진짜 request 객체를 호출한다.
6. 결론
- 지금까지 Bean이 가질 수 있는 다양한 Scope에 대해 배우면서,
Bean Scope에 따라 발생하는 문제와 해결방법을 알아보았다.
- Scope에 따라 Bean Lifecycle이 다르므로, 이 점을 유의하여 사용하도록 하자.
- 실무에서는 사실 Singleton Scope 외의 Scope을 잘 사용하지 않는다고 한다.
- 그러므로 Singleton Bean/Scope을 잘 사용하자.
'Back-end > Spring 개념' 카테고리의 다른 글
17. Spring 기본개념 총정리 (2) | 2022.02.18 |
---|---|
15. Bean 생명주기 콜백 (0) | 2022.02.16 |
14. Annotation을 만드는 방법 (0) | 2022.02.15 |
13. @Autowired의 다양한 문제 해결방법 (0) | 2022.02.14 |
12. Dependency Injection 방법 (0) | 2022.02.11 |
댓글