목차
왜 웹에 싱글톤이 사용되는지
스프링은 기업용 온라인 서비스 기술을 지원하기 위해 탄생
대부분의 스프링 애플리케이션은 웹 애플리케이션. 물론 웹이 아닌 애플리케이션 개발도 얼마든지 개발 가능 (batch, damon…)
웹 애플리케이션은 보통 여러 고객이 동시에 요청
package hello.core.singleton;
import hello.core.AppConfig;
import hello.core.member.MemberService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class SingleTonTest {
@Test
@DisplayName("스프링 없는 순수한 DI 컨테이너")
void pureContainer(){
AppConfig appConfig = new AppConfig();
//1. 조회: 호출할 때 마다 객체를 생성
MemberService memberService1 = appConfig.memberService();
//2. 조회: 호출할 때 마다 객체를 생성
MemberService memberService2 = appConfig.memberService();
//참조값이 다른 것을 확인
System.out.println("memberService1 = " + memberService1);
System.out.println("memberService2 = " + memberService2);
}
}

객체를 호출할 때마다 생성해서 반환하기 때문에 참조 값이 다른 것을 확인할 수 있다.
❗굉장히 비효율적인 방법
클래스의 인스턴스가 딱 1개만 생성되는 것을 보장하는 디자인 패턴
객체 인스턴스를 2개 이상 생성하지 못하도록 막아야 한다.
싱글톤 패턴을 적용한 코드
*main이 아닌 test 위치에 생성
package hello.core.singleton;
public class SingleTonService {
//클래스 레벨에 올라가기 때문에 딱 하나의 객체만이 생성됨
private static final SingleTonService instance = new SingleTonService();
//1. 객체 하나 생성 후 (private이므로 외부에서 객체 인스턴스 생성이 불가능하다.)
//2. instance에 참조로 넣어놓음
//3. 조회할 때 instance를 조회
public static SingleTonService getInstance(){
return instance;
}
private SingleTonService(){
}
public void logic(){
System.out.println("싱글톤 객체 로직 호출");
}
}
getInstance() 메서드를 통해서만 조회할 수 있다. 이 메서드를 호출하면 항상 같은 인스턴스를 반환한다. @Test
@DisplayName("싱글톤 패턴을 적용한 객체 사용")
void singletonServiceTest(){
SingletonService singletonService1 = SingletonService.getInstance();
SingletonService singletonService2 = SingletonService.getInstance();
System.out.println("singletonService1 = " + singletonService1);
System.out.println("singletonService2 = " + singletonService2);
}
이렇게 instance로 참조하면 같은 객체를 반환하는 것을 확인할 수 있다.

<aside> 💡 참고: 싱글톤 패턴을 구현하는 방법은 여러가지가 있다. 여기서는 객체를 미리 생성해두는 가장 단순하고 안전한 방법을 선택했다.
</aside>
싱글톤 패턴을 적용하면 고객의 요청이 올 때마다 객체를 생성하는 것이 아니라, 이미 만들어진 객체를 공유해서 효율적으로 사용할 수 있다. 하지만 싱글톤 패턴은 다음과 같은 수 많은 문제점을 가지고 있다.
싱글톤 패턴의 문제점
싱글톤 패턴을 구현하는 코드 자체가 많이 들어간다.
private static final SingleTonService instance = new SingleTonService();
public static SingleTonService getInstance(){
return instance;
}
private SingleTonService(){
}
의존 관계상 클라이언트가 구체 클래스에 의존한다 → DIP를 위반한다.
클라이언트가 구체 클래스에 의존해서 OCP 원칙을 위반할 가능성이 높다.
테스트하기 어렵다.
내부 속성을 변경하거나 초기화하기 어렵다.
private 생성자로 자식 클래스를 만들기 어렵다.
결론적으로 유연성이 떨어진다.
안티패턴으로 불리기도 한다.
스프링 컨테이너는 싱글톤 패턴의 문제점을 해결하면서, 객체 인스턴스를 싱글톤 (1개만 생성)으로 관리한다. 지금까지 배운 스프링 빈이 바로 싱글톤으로 관리되는 빈이다.