꼬물꼬물
싱글톤 컨테이너 [싱글톤 패턴] 본문
웹 애플리케이션과 싱글톤
- 객체 인스턴스가 JVM 내에 하나만 존재한다.
- 스프링은 기업용 론라인 서비스 기술을 지원하기 위해 탄생하며 웹 애플리케이션이다.
- 웹 애플리케이션은 보통 여러 고객이 동시에 요청한다.
public class SingletonTest {
@Test
@DisplayName("스프링 없는 순수한 DI 컨테이너")
void pureContainer(){
AppConfig appConfig = new AppConfig();
//1. 조회: 호출할 때마다 객체 생성
MemberService memberService1 = appConfig.memberService();
MemberService memberService2 = appConfig.memberService();
System.out.println("memberService1 = "+memberService1);
System.out.println("memberService2 = "+memberService2);
// memberService1 != memberService2
Assertions.assertThat(memberService1).isNotSameAs(memberService2);
}
}
// 결과
memberService1 = hello.core.member.MemberServiceImpl@6913c1fb
memberService2 = hello.core.member.MemberServiceImpl@66d18979 <- 다른 객체를 사용하고 있다.
- 스프링 없는 순수 DI 컨테이너인 AppConfig는 요청할 때 마다 객체를 새로 생성했다.
- 고객 트래픽이 초당 100이 나오면 초당 100개 객체가 생성되고 소멸된다 <- 메모리 낭비!
- ▶️ 해당 객체가 하나만 생성되고 공유하도록 설계하자 -> 싱글톤 패턴!
싱글톤 패턴
- 클래스의 인스턴스가 딱 1개만 생성되는 것을 보장하는 디자인 패턴
- 객체 인스턴스를 2개 이상 생성하지 못하도록 막는다.
- private 생성자를 사용해 외부에서 임의로 new 키워드를 사용하지 못하도록 막자
package hello.core.singleton;
public class SingletonService {
// 자기 자신을 내부에 private 으로 가진다. static을 통해 해당 클래스 내에서만 사용하기 대문에 딱 하나만 생성된다.
// java 싱행될 때 static 영역이 초기화되고 올라간다.
private static final SingletonService instance = new SingletonService();
public static SingletonService getInstance(){
return instance;
}
// private 생성자를 사용해 외부에서 new로 객체 생성을 막는다.
private SingletonService(){
}
public void logic(){
System.out.println("싱글톤 객체 로직 호출");
}
}
public static void main(String[] args) {
// 생성자가 private이라 생성 불가
SingletonService singletonService = new SingletonService();
}
- static 영역에 객체 instance를 미리 하나 생성해 올려둔다.
- 이 객체 인스턴스가 필요하면 getInstance()를 통해서만 조회할 수 있다. 해당 메서드는 항상 같은 인스턴스를 반환한다.
- 딱 1개의 객체 인스턴스만 존재해야 하므로, 생성자를 private으로 막아 외부에서 new로 객체 인스턴스 생성되는 것을 막는다.
@Test
@DisplayName("싱글톤 패턴을 적용한 객체 사용")
void singletonServiceTest(){
SingletonService singletonService1 = SingletonService.getInstance();
SingletonService singletonService2 = SingletonService.getInstance();
System.out.println("singletonService1 = "+singletonService1);
System.out.println("singletonService2 = "+singletonService2);
assertThat(singletonService1).isSameAs(singletonService2);
// Same ==
// Equal isEqualTo
}
// 결과
singletonService1 = hello.core.singleton.SingletonService@2de23121
singletonService2 = hello.core.singleton.SingletonService@2de23121 <- 같은 객체 인스턴스 반환
- Same은 ==
- Equal은 isEqualTo
- private으로 new 키워드를 막아 new SingletonService()가 실행되지 않는다.
- 호출할 때마다 같은 객체 인스턴스를 반환하고 있다.
- + 싱글톤 패턴을 구현하는 방법은 여러가지 있따. 객체를 미리 생성해두는 가장 단순한 방법 선택
✅ 싱글톤 패턴을 적용하면 고객의 요청이 올 때마다 객체를 생성하는 것이 아니라, 이미 만들어진 객체를 공유해 효율적으로 사용할 수 있다. 하지만 수많은 문제점을 갖는다.
🚨 싱글톤 패턴의 문제점
- 구현하는 자체의 코드가 늘어난다.
- 의존관계 상 클라이언트가 구체 클래스에 의존 <- DIP 위반
- 클라이언트가 구체 클래스에 의존해 OCP 원칙을 위반할 가능성이 높다.
- 테스트가 어려움
- 내부 속성 변경, 초기화가 어렵다.
- private 생성자로 자식클래스 생성이 어려움
- 결론적으로 유연성 떨어짐 -> 안티 패턴으로 불리기도 한다.
스프링 프레임워크가 싱글톤 패턴의 문제점을 제거한다!
'스터디 > 스프링 핵심 원리 - 기본편' 카테고리의 다른 글
싱글톤 컨테이너 [@Configuration] (0) | 2022.09.18 |
---|---|
싱글톤 컨테이너 [싱글톤 컨테이너] (0) | 2022.09.17 |
스프링 컨테이너와 스프링 빈 [스프링 컨테이너 생성과 스프링 빈 조회] (0) | 2022.09.14 |
스프링 핵심 원리 이해2 - 객체 지향 원리 적용 [IoC, DI 그리고 컨테이너, 스프링 전환] (0) | 2022.09.12 |
스프링 핵심 원리 이해2 - 객체 지향 원리 적용 [새로운 구조와 할인 정책 적용, 좋은 객체 지향 설계] (0) | 2022.09.12 |