싱글톤 컨테이너

Min
5 min readMay 16, 2021
썸네일

김영한님의 스프링 핵심 원리 — 기본편 강의 내용 중 ‘5강. 싱글톤 컨테이너’에 대한 내용을 정리해봤다.

직전 강의 ‘4강. 스프링 컨테이너와 스프링 빈’에서는 스프링 컨테이너에서 빈을 생성하고 가져오는 방법들에 대해서 공부했다. (관련글 : https://velog.io/@ace0390/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88%EC%99%80-%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B9%88)

이번 강의에서는

  • 싱글톤 패턴
  • 왜 스프링 컨테이너가 주로 싱글톤으로 빈을 관리하는지
  • 어떻게 싱글톤 빈을 관리하는지

에 대해 공부한다.

웹 애플리케이션에서 싱글톤이 좋은 이유

다양한 애플리케이션이 있지만 그 중 웹애플리케이션의 특징 중 하나는 여러 종류의 요청을 동시에 처리해야 한다는 것이다.

만약 싱글톤 객체를 쓰지 않는다면 요청 마다 요청에 필요한 객체들을 새로 생성해야 할 것이고 이 객체들은 요청이 끝난 후 gc 의 대상이 될 것이다. 요청이 많아지면 빈번한 gc 로 인해 시스템에 악영향을 끼칠 수 있다.

요청에 필요한 객체들을 미리 싱글톤 객체로 생성해 놓고 사용하면 위의 문제를 해결할 수 있다.

싱글톤 패턴

클래스의 인스턴스가 메모리상에 1개만 생성되는 것을 보장하는 디자인 패턴이다.

싱글톤 예제

static 키워드와 private 생성자를 이용해 애플리케이션이 올라갈때 SingletonService 객체가 method area 에 하나만 생성되게 함으로써, SingletonService 객체는 메모리에 단 하나만 존재하게 된다.

SingletonService 가 필요한 곳에서는 아래와 같은 코드로 SingletonService 객체를 가져와 사용할 수 있다.

SingletonService singletonService = SingletonService.getInstance();

싱글톤 패턴 주의점

싱글톤 패턴은 여러 클라이언트가 하나의 같은 객체 인스턴스를 공유하기 때문에 싱글톤 객체가 상태를 유지하면 안된다.

  • 특정 클라이언트가 값을 변경할 수 있는 필드가 있으면 안된다.
  • 읽기만 가능해야 한다.
  • 클래스 변수가 아닌 지역변수, ThreadLocal 등을 사용해야 한다.

싱글톤 패턴 단점

싱글톤 패턴은 위와 같은 장점도 있지만 단점도 존재한다.

  • 클라이언트가 구체 클래스의 의존한다. => DIP 위반
  • 클라이언트가 구체 클래스에 의존하기 때문에 OCP 원칙을 위반할 가능성이 높다.
  • 여러 테스트 세트내에서 하나의 인스턴스가 그 상태를 유지하기 때문에 테스트가 어렵다.
  • private 생성자 때문에 자식 클래스를 만들기 어렵다.

싱글톤 컨테이너

  • 스프링 컨테이너는 싱글턴 패턴을 적용하지 않아도, 객체 인스턴스를 싱글톤으로 관리한다.
  • 스프링 컨테이너 덕분에 싱글턴 패턴의 단점들을 해결하면서 객체를 싱글톤으로 유지할 수 있다.

@Configuration 어노테이션과 싱글톤

빈을 정의하고 있는 AppConfig.java 코드를 보자

AppConfig.class

AppConfig.memberService() 메서드는 new 연산자로 MemberServiceImpl 객체를 생성하고 있다.

memberService1 == memberService2 test

위 코드에서는 appConfig.memberService() 를 2번 호출 후 메서드 결과의 인스턴스가 같은 인스턴스 인지 비교하고 있다.

자바 코드만 놓고 본다면 AppConfig.memberService() 에서 MemberSerivceImpl 객체를 매번 생성하므로 해당 테스트는 실패해야할 것처럼 보이나 성공한다.

memberService1 == memberService2

위에서 설명했듯이 스프링에서 기본적으로 싱글톤으로 빈을 관리하기 때문이다. 하지만 자바 코드상 분명 실패해야 하는 테스트인데 스프링은 어떻게 memberSerivce 를 싱글톤으로 유지하는 것일까?

@Configuration @Bean

appConfig 객체는 우리가 만든 AppConfig 클래스의 객체가 아닌 스프링이 cglib 라이브러리로 만든 프록시 클래스다. (위의 스크린샷에서 appConfig 를 출력한 것을 보자)

프록시 클래스 내에서 @Bean 이 붙은 메서드 마다 이미 빈이 존재하면 존재하는 빈을 반환하고, 빈이 없다면 생성해서 빈으로 등록하고 반환하는 코드가 동적으로 만들어 지는 것이다.

이렇게 스프링 컨테이너를 사용하면 싱글톤 빈을 보장받을 수 있다.

--

--