본문 바로가기
Back-end/Spring 개념

7. Singleton Container

by devraphy 2022. 2. 2.

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

댓글