0. 개요
- Spring Container의 다른 이름이 Singleton Container이다.
- Spring Container가 Bean을 Singleton 방식으로 관리하기 때문에 붙여진 이름이다.
- 이번 포스팅에서는 Singleton Container에 대해서 알아보도록 하자.
1. Spring이 Singleton을 사용하는 이유
- Spring 프레임 워크는 기업용 웹 서비스를 지원하기 위해 등장한 기술이다.
- 기업용 웹 서비스는 다수의 사용자가 동시적으로 서버에게 요청을 보낸다.
- 이러한 다수의 동시 요청을 오류 없이 처리하기 위해 Singleton 방식을 사용한다.
a) 다수의 요청을 처리하는 방법
- 고객의 요청마다 객체를 새롭게 생성한다고 가정해보자.
- 서비스 트래픽이 초당 100이라면, 초당 100개의 요청이 발생하고, 초당 100개의 객체가 생성된다.
- 이러한 방식은 메모리가 낭비가 심하며, 객체를 생성하는 과정으로 인해 오히려 서비스 응답 시간이 오래 걸린다.
- 그러면 1개의 객체만 이용해서 100개의 요청을 순서대로 처리한다면 더 효율적이지 않을까?
- 그 방법이 Singleton이다.
2. Singleton 이란?
- Client에서 request를 보내면 서버에서는 컨트롤러를 통해, 해당 요청을 처리할 수 있는 서비스를 호출하게 된다.
- 호출된 서비스는 비즈니스 로직을 수행하면서, 이에 필요한 다양한 객체를 호출한다.
- 이때 객체를 매번 생성하지 않고, 클래스당 하나의 객체만을 생성한다.
- 각 클래스마다 생성된 한 개의 객체를 공유하여 요청을 처리하는 방식을 Singleton이라 한다.
3. Singleton을 구현하는 방법
a) Static 접근 지정자를 이용한 Singleton
- 객체를 생성할 때, static을 붙여서 Class 레벨의 객체로 등록한다(Java 기능).
- 그리고 외부에서 생성자를 통해 객체를 추가 생성할 수 없도록 Constructor에 private접근 지정자를 붙인다.
- 이와 같은 방식으로 Class 레벨에 객체를 등록한다면, 단 1개의 객체만 생성이 가능하며, 추가적인 생성이 불가하다.
b) Static 방식의 문제점
- Static을 사용한 방식은 client에서 직접 구현체를 생성해야 된다. 이는 OCP, DIP의 위반이다.
- 더불어 생성자를 private으로 설정하기 때문에 자식 클래스를 생성하는데 어려움이 있다.
- 그렇다면 어떻게 해야 할까? 외부에서 누군가 대신해주면 된다.
- Spring Container가 그 역할을 수행한다.
c) Spring Container를 이용한 Singleton
- Spring Conatiner는 Singleton Container라고 불린다.
- 그 이유는 Spring Container가 Bean을 Singleton 방식으로 관리하기 때문이다.
- Spring Contianer에 등록된 Bean(= 객체)은 App 빌드 시점에서 단 한 번만 객체(= Bean)를 생성한다.
- 이후 필요한 Bean은 Spring Container에게 요청하여 사용한다.
- Spring Framework에서 이 모든 기능을 자동으로 적용해준다.
- 이처럼, Singleton 방식으로 객체를 생성 및 관리하는 기능을 Singleton Registry라고 한다.
d) Spring에서 Singleton 사용 시 주의사항
- Singleton은 다양한 client에서 하나의 객체를 공유하는 방식을 사용한다.
- 그러므로 공유되는 객체의 상태를 유지(stateful)해서는 안된다.
- 즉, 무상태(stateless)로 설계되어야 하는데 이는 다음과 같은 조건을 의미한다.
→ 특정 client에 의존적인 필드(= 멤버 변수)가 있으면 안 된다.
→ 특정 client만 변경할 수 있는 필드가 있으면 안 된다.
→ 가급적 client는 객체의 데이터를 읽기만 가능해야 된다.
→ 즉, 필드 대신 공유되지 않는 지역변수, 파라미터 등을 사용해야 한다.
- 이처럼 무상태를 유지하는 이유는 다양한 모듈에서 공유되는 객체이기 때문이다.
- 만약 객체 내부에서 공유되는 값을 가지고 있다면, 이는 잘못된 연산으로 큰 장애를 발생시킬 수 있다.
4. Stateful과 Stateless
e) 상태(stateful)란?
- 객체가 사용된 이후에 객체의 값이 초기화되지 않고 그대로 남아있는 상태를 말한다.
- 이 경우, 변질된 값을 가진 객체로 인해 다른 요청을 처리할 때 잘못된 결과를 만든다.
- 즉, 이전의 상태를 기억한다.
- 그러므로 Singleton은 절대로 상태를 가지면 안 된다.
f) 무상태(stateless)란?
- 객체가 사용된 이후에 객체의 값이 초기화되는 것을 말한다.
- 이 경우, 다양한 요청을 처리하기 위해 호출되어도 객체의 초기 값이 동일하므로 기대한 결과 값을 만든다.
- 즉, 이전의 상태를 기억하지 못한다.
- 그러므로 Singleton은 반드시 무상태를 유지해야 한다.
5. @Configuration과 Singleton
a) Spring Bean이 Singleton으로 보장되는 이유
- AppConfig(= 설정 파일)에 @Configuration을 붙여, Spring에게 해당 파일이 설정 파일임을 인지시킨다.
- Spring이 @Configuration을 확인하면, 내부의 @Bean을 찾아서 Singleton으로 Container에 등록한다.
- 이 과정에서 검색된 @Bean의 이름이 Container에 이미 존재하는지 조회한다.
- Container에 존재하지 않는 Bean은 생성자를 통해 객체를 생성하고, 반대의 경우 스킵한다.
- 이 과정을 거쳐 Spring Container는 Bean을 Singleton으로 관리한다.
@Configuration
public class AppConfig {
@Bean
public TestService testService() {
return new TestServiceImpl(testRepository());
}
}
b) @Configuration이 Singleton을 보장한다.
- 설정 파일을 AnnotationConfigApplicationContext의 파라미터로 넘기면,
Spring은 이 설정 파일을 Spring Bean으로 등록한다.
- 그러나 설정 파일 Bean의 클래스를 확인해보면 CGLIB이라는 클래스명이 붙어있다.
bean = class hello.core.AppConfig$$EnhancerBySpringCGLIB$$bd479d70
- CGLIB은 설정 파일에 @Configuration이 명시되어 있을 때만 작동한다.
- CGLIB은 바이트 조작 라이브러리로, 이를 이용하여 설정 파일을 복제하여 임의의 클래스를 생성한다.
- 이렇게 생성된 임의의 클래스는 Spring Bean으로 등록된다.
- 이 임의의 클래스는 설정 파일을 상속받은 자식 클래스이며, Singleton을 보장하는 핵심 역할을 한다.
c) @Configuration이 없으면 Singleton이 보장되지 않는다.
- 설정 파일에 @Configuration이 없다면 Spring은 Singleton을 보장하지 않는다.
- CGLIB에 의해 복제된 클래스가 생성되지 않기 때문이다.
bean = class hello.core.AppConfig
- 앞서 CGLIB에 의해 생성된 클래스가 싱글톤을 보장하는 핵심 역할을 한다고 설명했다.
- 그러므로 @Configuration이 없는 설정 파일을 Spring Container로 등록한다면 Singleton은 보장되지 않는다.
- 즉, 매번 요청이 들어올 때마다 새로운 객체가 생성된다.
'Back-end > Spring 개념' 카테고리의 다른 글
9. @ComponentScan의 동작원리와 옵션 (0) | 2022.02.08 |
---|---|
8. Bean 자동 등록 (0) | 2022.02.07 |
6. Spring Container의 다형성 (0) | 2022.02.01 |
5. Spring Container (0) | 2022.01.31 |
4. Spring을 사용하는 이유 (1) | 2022.01.27 |
댓글