싱글톤 컨테이너

Kooks·2026년 4월 29일

Spring

목록 보기
2/6
post-thumbnail

싱글톤 패턴

  • 클래스의 인스턴스가 1개만 생성되는 것을 보장하는 디자인 패턴
  • 객체 인스턴스를 2개 이상 생성하지 못하도록 막아야 한다.
  • private 생성자를 사용해서 외부에서 임의로 new 키워드를 사용하지 못하도록 막아야한다.
public class SingletonService{

	//1. static 영역에 객체를 1개만 생성
	private static final SingletonService instance = new SingletonService();
    
    //2. public으로 열어서 객체 인스턴스가 필요하면 이 static 메서드를 통해서만 조회하도록 허용
    public static SingletonService getInstance(){
    	return instance;
    }
    
    //3. 생성자를 private로 선언해서 외부에서 new 키워드를 사용한 객체 생성을 못하게 막는다.
    private SingletonService(){}
    
    public void logic(){
    	System.out.println("싱글톤 객체 로직 호출");
    }

}
  1. static 영역에 객체 instance를 미리 하나 생성해서 올려둔다.
  2. 객체 인스턴스가 필요하면 오직 getInstance() 메서드를 통해서만 조회할 수 있다. 이 메서드를 호출하면 항상 같은 인스턴스를 반환한다.
  3. 1개의 객체 인스턴스만 존재하므로, 생성자를 private로 막아서 혹시라도 외부에서 new 키워드로 객체 인스턴스가 생성되는 것을 막는다.

싱글톤 패턴을 적용하면 고객의 요청이 올 때 마다 객체를 생성하는 것이 아니라, 이미 만들어진 객체를 공유해서 효율적으로 사용할 수 있다.

싱글톤패턴 문제점

  • 싱글톤 패턴을 구현하는 코드 자체가 많이 들어간다.
  • 의존관계상 클라이언트가 구체 클래스에 의존한다. -> DIP를 위반한다.
  • 클라이언트가 구체 클래스에 의존해서 OCP 원칙을 위반할 가능성이 높다.
  • 테스트하기 어렵다.
  • 내부 속성을 변경하거나 초기화하기 어렵다.
  • private 생성자로 자식 클래스를 만들기 어렵고, 유연성이 떨어진다.
  • 안티패턴으로 불리기도 한다.

싱글톤 컨테이너

스프링 컨테이너는 싱글톤 패턴의 문제점을 해결하면서, 객체 인스턴스를 싱글톤으로 관리한다.

  • 스프링 컨테이너는 싱글톤 패턴을 적용하지 않아도, 객체 인스턴스를 싱글톤으로 관리한다.
  • 스프링 컨테이너는 싱글톤 컨테이너 역할을 한다. 싱글톤 객체를 생성하고 관리하는 기능을 싱글톤 레지스트리라 한다.
  • 싱글톤 패턴의 모든 단점을 해결하면서 객체를 싱글톤으로 유지할 수 있다.

주의점

  • 객체 인스턴스를 하나만 생성해서 공유하는 싱글톤 방식은 여러 클라이언트가 하나의 같은 객체의 같은 객체 인스턴스를 공유하기 때문에 싱글톤 객체는 상태를 유지(stateful)하게 설계하면 안된다.
  • 무상태(stateless)로 설계해야 한다.
  • 의존적인 필드, 값을 변경할 수 있는 필드가 있으면 안된다.
  1. 무상태로 만들라는 건 필드를 아예 쓰지 말라는 뜻이 아니라, 요청마다 달라지는 값을 필드에 저장하지 말라는 뜻
  2. Repository, Service, Client 같은 의존 객체를 final 필드로 주입받는 것은 괜찮
  3. userId, price, currentOrder처럼 사용자별로 달라지는 값은 필드가 아니라 파라미터, 지역 변수, 반환값으로 처리해야 함

@Configuration과 바이트코드 조작

스프링 컨테이너는 싱글톤 레지스트리다. 따라서 스프링 빈이 싱글톤이 되도록 보장해주어야 한다. 그런데 스프링이 자바 코드까지 어떻게 하기는 어렵다. 자바 코드는 여러번 호출될 수 있다. 그래서 스프링은 클래스의 바이트코드를 조작하는 라이브러리를 사용한다.
모든 비밀은 @Configutation을 적용한 AppConfig에 있다.

  • AnnotationConfigApplicationContext에 파라미터로 넘긴 값은 스프링 빈으로 등록된다. 그래서 AppConfig도 스프링 빈이 된다.

프록시 적용 대상

  • "스프링이 메서드 호출을 가로채야 하는 이유가 있는지"로 정한다.
  • 비즈니스 빈 -> 객체 하나 만들고 주입하면 싱글톤 보장 끝, 기본 프록시 불필요
  • @Configuration, @Transactional, @Cacheable, @Async <- 프록시 대상

정리

  • 비즈니스 빈은 스프링 컨테이너가 객체를 한 번 생성하고, 등록된 빈을 의존성으로 주입하면 되므로 싱글톤 보장을 위한 프록시가 필요없다.
  • 반면 @Configuration은 @Bean 메서드가 여러 번 직접 호출될 수 있으므로, 스프링이 프록시로 호출을 가로채 기존 싱글톤 빈을 반환
  • @Configuration이 적용된 설정 클래스의 @Bean 메서드라면, 여러 번 생성하는 코드처럼 보여도 프록시가 가로채서 이미 등록된 빈을 반환
profile
I'm kooks

0개의 댓글