Hazel Han 2023. 11. 19. 17:45

싱글톤 패턴

클래스의 인스턴스가 딱 1개만 생성되는 것을 보장하는 디자인 패턴

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("싱글톤 객체 로직 호출");
 
 }
}

 

싱글톤 패턴의 사용 이유

  • 최초에 한번만 메모리를 할당하고, 그곳에 인스턴스를 만들기 때문에 메모리 낭비를 방지할 수 있다.
  • 다른 클래스 등 어디에서나 접근가능하다.

하지만 싱글톤 패턴은 DIP를 위반하거나, OCP 위반 가능성이 있다는 등의 문제점이 있다.

따라서 싱글톤 컨테이너라는 것을 사용한다.

 

 

싱글톤 컨테이너

싱글톤 패턴의 문제점을 해결하며, 객체 인스턴스를 싱글톤으로 관리한다.

스프링 컨테이너는 이 싱글톤 컨테이너와 같은 역할을 해준다. 이러한 기능을 시글톤 레지스트리라고 한다.

 

스프링 컨테이너를 사용한 테스트 코드

@Test
@DisplayName("스프링 컨테이너와 싱글톤")
void springContainer() {

 ApplicationContext ac = newAnnotationConfigApplicationContext(AppConfig.class);

 //1. 조회: 호출할 때 마다 같은 객체를 반환
 MemberService memberService1 = ac.getBean("memberService", MemberService.class);
 //2. 조회: 호출할 때 마다 같은 객체를 반환
 MemberService memberService2 = ac.getBean("memberService", MemberService.class);
 //참조값이 같은 것을 확인
 System.out.println("memberService1 = " + memberService1);
 System.out.println("memberService2 = " + memberService2);
 //memberService1 == memberService2
 assertThat(memberService1).isSameAs(memberService2);
 
}

 

싱글톤 방식의 주의점

특정 변수를 클라이언트가 변경할 가능성이 있다.

따라서 공유필드를 조심해야하며, 항상 *무상태(stateless)상태로 설계해야한다.

*무상태(stateless) : 예를 들어 return만 있거나 하든 등의 변경 가능한 상태가 없는 것을 의미한다.

 

 

@Configuration과 싱글톤

종종 싱글톤이 적용되지 않는 상황이 발생하곤 한다. 이 때는 바이트코드를 조작해서 사용해야하는데, @Bean이 붙은 메서드마다 이미 빈이 존재하면 반환하고, 그렇지 않으면 생성하여 스프링 빈으로 등록 후 반환한다.

그냥 간단하게 생각해서 스프링 설정 정보는 모두 @Configuration을 사용하도록 하자.