스프링 프레임워크(Spring Framework) 톺아보기 - 싱글톤 컨테이너(Singleton Container)

Janek·2023년 1월 3일
0

Spring 톺아보기

목록 보기
3/10
post-thumbnail
post-custom-banner

해당 포스팅은 인프런에서 제공하는 김영한 님의 '스프링 핵심원리 기본편'을 수강한 후 정리한 글입니다. 유료 강의를 정리한 내용이기에 제공되는 예제나 몇몇 내용들은 제외하였고, 정리한 내용을 바탕으로 글 작성자인 저의 언어로 다시 작성한 글이기에 서술이 부족하거나 잘못된 내용이 있을 수 있습니다. 그렇기에 해당 글은 개념에 대한 참고 정도만 해주시고, 강의를 통해 학습하시기를 추천합니다.

스프링 어플리케이션은 대부분 웹 어플리케이션이며, 웹 어플리케이션은 보통 여러 요청이 동시에 들어온다. 만약 특정 객체에 대한 요청이 반복적으로 들어온다면, 해당 객체는 요청 수 만큼 생성되고, 소멸될 것이다. 이는 심각한 메모리 낭비이며, 이를 해결하기 위해 딱 한개의 객체만을 생성하고, 공유하게 만드는 것이 바로 싱글톤 패턴이다.

싱글톤 패턴(Singleton pattern)

싱글톤 패턴은 클래스의 인스턴스가 딱 한 개만 생성되도록 보장하는 디자인 패턴이다. 따라서 동일한 인스턴스가 두 개 이상 생성되지 못하도록 private 생성자를 사용해 외부에서 임의로 인스턴스를 생성하지 못하도록 막아야 한다.

public class SingletonClass {
	// static 영역에 객체를 딱 한개만 생성해둔다. 
	private static final SingletonClass instance = new SingletonClass();
    
    // public 메서드를 통해 객체 인스턴스를 조회할 수 있도록 허용한다.
    public static SingletonClass getInstance() {
    	return instance;
    }
    
    // 생성자를 private으로 선언해서 외부에서 생성하지 못하도록 막는다.
    private SingletonClass() {}
}

싱글톤 패턴을 적용할 경우 요청에 따라 새로운 객체를 생성하는 것이 아닌 이미 만들어진 객체를 공유해서 효율적으로 사용할 수 있다는 장점이 있지만, 다음과 같은 문제점들을 수반한다.

  • 싱글톤 패턴 구현을 위해 코드를 작성하는 비용이 증가한다.
  • 클라이언트가 구체 클래스에 의존하게 되면서 DIP를 위반하게 되며 OCP 원칙을 위반할 가능성이 높아진다.
  • 테스트가 어려워진다.
  • 객체를 초기화 하거나 내부 속성을 변경하기 어렵다.
  • private 생성자를 사용하기 때문에 자식 객체를 생성하기 어렵다.
  • 위의 문제점들로 인해 유연성이 떨어지며, 안티 패턴으로 불리기도 한다.

싱글톤 컨테이너(Singleton Container)

스프링 컨테이너는 싱글톤 패턴의 문제점들을 보완하면서 객체 인스턴스를 싱글톤으로 관리해준다. 이렇게 스프링 컨테이너에서 싱글톤으로 관리해주는 객체가 바로 스프링 빈이다.

싱글톤 레지스트리

스프링 컨테이너는 싱글톤 패턴을 적용하지 않아도 객체를 하나만 생성해서 관리하며, 이렇게 싱글톤 객체를 생성하고 관리하는 기능을 싱글톤 레지스트리라고 한다. 스프링 컨테이너를 통해 싱글톤 객체를 생성/관리할 경우 객체를 싱글톤으로 생성하기 위한 코드가 필요하지 않아 코드 작성 비용이 증가하지 않으며, DIP, OCP, 테스트, private 생성자로 부터 자유롭게 싱글톤을 사용할 수 있다.

싱글톤 방식의 주의점

객체 인스턴스를 하나만 생성해서 공유하는 싱글톤 방식은 여러 객체가 하나의 같은 인스턴스를 공유하기 때문에 싱글톤 객체는 상태를 유지(stateful)하게 설계하면 안된다. 다음은 객체를 무상태(stateless)로 설계하는 방법이다.

  • 특정 클라이언트에 의존적인 필드가 있으면 안된다.
  • 특정 클라이언트가 값을 변경할 수 있는 필드가 있으면 안된다.
  • 가급적 읽기만 가능해야 한다.
  • 필드 대신에 자바에서 공유되지 않는 지역변수, 파라미터, ThreadLocal 등을 사용해야 한다.

@Configuration

바이트코드 조작

스프링 컨테이너는 싱글톤 레지스트리이기 때문에 스프링 빈이 싱글톤이 되도록 보장해주어야 한다. 하지만 스프링 프레임워크가 자바 코드까지 조작할 수는 없기 때문에 클래스의 바이트코드를 조작하는 CGLIB라이브러리를 사용한다.

@Configuration
public class AppConfig {
// 스프링에 등록될 때 원본 객체가 아닌 해당 객체를 상속받은 CGLIB 객체가 등록된다.
// AppConfig를 상속받은 객체가 등록되는 것이기 때문에 AppConfig 타입으로 조회 가능

	@Bean
	public Singleton singleton() {
 		return new Singleton();	
        // 어느 객체에서 호출되던지 싱글톤이 보장된다.
 	}
    
 ...
}

@Configuration이 선언된 객체는 스프링에 의해 해당 객체를 상속받은 CGLIB 객체로 대체되며, 해당 객체의 @Bean 메서드를 통해 객체를 반환할 때마다 스프링 빈이 있으면 그 객체를 반환하고, 없다면 생성하여 빈으로 등록하고 반환하는 동적인 코드가 만들어진다. 그렇기 때문에 싱글톤이 보장되는 것이다.

@Bean 어노테이션만 선언하여도 스프링 빈으로 등록은 되지만 @Configuration 없이는 싱글톤이 보장되지 않는다.

profile
만들고 나누며, 세상을 이롭게 하고 싶습니다.
post-custom-banner

0개의 댓글