728x90
싱글톤 패턴(Singleton Pattern)
- 애플리케이션이 시작될 때 어떤 클래스가 최초로 한 번만 메모리를 할당하고, 해당 메모리에 인스턴스를 만들어 여러 객체에서 하나의 인스턴스를 참조하여 사용하는 패턴
- 장점
- 인스턴스가 필요할 때 기존의 인스턴스를 사용하므로 new를 통해 같은 객체를 여러 개 생성하여 메모리를 낭비하는 것을 방지할 수 있다.
- 싱글톤으로 구현한 인스턴스는 전역이므로, 여러 객체가 공유하여 사용하는 데에서 오는 여러 장점이 있다.
- 단점
- 싱글톤 인스턴스에 많은 객체가 결합되어 있어 결합도가 높아지면 문제가 생겼을 때 에러 복구하기가 굉장히 힘들다
- 멀티 스레드 환경해서 동기화 처리가 제대로 되지 않으면 인스턴스가 2개 생성되는 문제가 발생할 수 있다는 점이 있다.
- 싱글톤 패턴을 구현하는 코드 자체가 많이 들어간다.
- 의존 관계상 클라이언트가 구체 클래스에 의존한다.(DIP 위반)
- private 생성자로 자식 클래스를 만들기 어려워 결론적으로 유연성이 떨어진다.
스프링없는 순수한 DI 컨테이너
AppConfig appConfig = new AppConfig(); // 1. 조회: 호출할 때 마다 객체를 생성
MemberService memberService1 = appConfig.memberService(); // 1. 조회: 호출할 때 마다 객체를 생성
MemberService memberService2 = appConfig.memberService(); // 2. 조회: 호출할 때 마다 객체를 생성
//참조값이 다른 것을 확인
System.out.println("memberService1 = " + memberService1);
System.out.println("memberService2 = " + memberService2);
//memberService1 != memberService2
assertThat(memberService1).isNotSameAs(memberService2); // 참조값이 다르게 나온다.
싱글톤 컨테이너
- 스프링 컨테이너는 싱글톤 패턴의 많은 문제(단점)를 해결함과 동시에 장점만을 이용할 수 있다.
- 따로 싱글톤 패턴을 적용하지 않아도, 객체 인스턴스를 싱글톤으로 관리한다.
- 스프링 컨테이너 덕분에 고객의 요청이 올 때마다 객체를 생성하는 것이 아닌, 이미 만들어진 객체를 공유해서 효율적으로 재사용할 수 있다.
- 스프링의 기본 빈 등록 방식은 싱글톤이지만, 싱글톤 이외의 방식도 지원한다.
싱글톤 방식을 사용할 때 주의할 점
- 싱글톤 패턴, 스프링과 같은 싱글톤 컨테이너를 사용할 때는 여러 클라이언트가 하나의 같은 객체 인스턴스를 공유하기 때문에 stateful(상태 유지)하게 설계해서는 안 된다.
- stateless(무상태)로 설계해야 한다.
- 특정 클라이언트에 의존적인 필드가 있으면 안 된다.
- 특정 클라이언트가 값을 변경할 수 있는 필드가 있으면 안 된다.
- 가급적 읽기만 가능해야 한다.
- 필드 대신에 자바에서 공유되지 않는 지역변수, 파라미터, ThreadLocal 등을 사용해야 한다.
ApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
StatefulService statefulService1 = ac.getBean("statefulService", StatefulService.class);
StatefulService statefulService2 = ac.getBean("statefulService", StatefulService.class);
//ThreadA: A사용자 10000원 주문
statefulService1.order("userA", 10000);
//ThreadB: B사용자 20000원 주문
statefulService2.order("userB", 20000);
//ThreadA: 사용자A 주문 금액 조회
int price = statefulService1.getPrice();
//ThreadA: 사용자A는 10000원을 기대했지만, 기대와 다르게 20000원 출력
System.out.println("price = " + price);
Assertions.assertThat(statefulService1.getPrice()).isEqualTo(20000); // true
@Configuration과 싱글톤
- @Configuration을 사용하게 되면 스프링이 CGLIB이라는 바이트코드 조작 라이브러리를 사용해서 사용자가 빈으로 등록하려는 클래스가 아닌, 임의의 다른 클래스를 만들어 스프링 빈으로 등록한다.
- CGLIB은 사용자가 빈으로 등록하려는 클래스의 자식 타입이다.
- 이 임의의 다른 클래스는 싱글톤이 보장되도록 도와준다.
- @Bean만 사용해도 스프링 빈으로 등록되지만, 싱글톤을 보장하디 않으므로, 스프링 설정 정보는 항상 @Configuration을 이용하면 된다.
@Bean
public MemberRepository memberRepository() {
if (memoryMemberRepository가 이미 스프링 컨테이너에 등록되어 있으면?) {
return 스프링 컨테이너에서 찾아서 반환;
}
else { //스프링 컨테이너에 없으면
기존 로직을 호출해서 MemoryMemberRepository를 생성하고 스프링 컨테이너에 등록
return 반환
}
}
// 싱글톤이 보장되도록 해줌
참고 :
https://gyoogle.dev/blog/design-pattern/Singleton%20Pattern.html
김영한 - 스프링 핵심 원리
728x90
'넓고 얕은 CS 지식' 카테고리의 다른 글
멀티 프로세스와 멀티 스레드 (0) | 2023.03.08 |
---|---|
동기 & 비동기 / 블로킹 & 논블로킹 3분 요약 정리 (0) | 2023.03.07 |
컨텍스트 스위칭 & PCB 10초 요약 정리 (0) | 2023.02.18 |
Git과 명령어 (0) | 2022.08.29 |
리눅스 터미널 (0) | 2022.08.26 |