*싱글톤 - 객체인스턴스가 자바에 딱 하나 있는 패턴.
<웹 애플리케이션과 싱글톤>
스프링은 기업용 온라인 서비스를 지원하기 위해 탄생한 기술.
스프링 애플리케이션은 대부분 웹 애플리케이션(웹 아니어도 개발 가능은 O).
웹 애플리케이션 -> 보통 여러 고객이 동시 요청.
(EX)
클라이언트 A,B,C가 멤버서비스를 스프링에 요청
(기존 코드)-> AppConfig에서 DI 컨테이너가 new MemberServiceImpl(memberRepository())로 멤버 서비스 생성해 반환. A에게 생성한거 반환 / B, C에게 또 생성해서 반환 =>고객 3명이 요청 시 객체 3개가 생성됨.
웹 애플리케이션은 고객이 계속 요청하는 형식이기에 요청마다 객체 만들어야 함. (비효율적)
-요청마다 객체 생성 되는지 테스트
#스프링 사용 안하는 순수한 DI컨테이너
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;
import static org.assertj.core.api.Assertions.*;
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);
//memberService1 != memberService2 멤버 1 != 멤버2인 것을 검증.
//눈으로 확인하는게 아닌 자동화 되게 테스트 코드 만들어야 함.
assertThat(memberService1).isNotSameAs(memberService2);
}
}
- 스프링 없는 순수한 DI 컨테이너인 AppConfig는 요청마다 객체 새로 생성.
- 만약 고객 트래픽이 초당 100이면 ? 초당 100개의 객체가 생성되고 소멸되는 것이기에 메모리 낭비가 심함(실제로는 트래픽이 100보다 크기에 메모리 낭비 심함.)
- 해결방안: 싱글톤 패턴 - 해당 객체가 1개만 생성되고, 공유하도록 설계 ~>효율적
<싱글톤 패턴>
-클래스 인스턴스가 딱 1개만 생성되게 보장하는 디자인 패턴
방법:객체 2개 이상 생성 제한.->private 생성자를 사용해 외부에서 임의로 new 키워드 사용 못하게 해야함. +)싱글톤 패턴 구현 방법은 정말 많음. 그중에 가장 단순하고 안전한 방법임.
package hello.core.singleton;
public class SingletonService {
//1. static 영역에 객체를 딱 1개만 생성해둔다.
//자바가 뜰 때 static영역에 new부분이 있으면 내부적으로 실행해서 객체를 생성하고 instance에 참조로 넣어놓음.
private static final SingletonService instance = new SingletonService();
//2. public으로 열어서 객체 인스터스가 필요하면 이 static 메서드를 통해서만 조회하도록
허용한다. 인스턴스의 참조를 꺼낼 수 있는 유일한 방법. 이 메소드 호출 시 항상 같은 인스턴스 반환.
->다른 곳에서 new로 객체 생성하지도, 조회하지도 못하게 됨.
public static SingletonService getInstance() {
return instance;
}
//3. 생성자를 private으로 선언해서 외부에서 new 키워드를 사용한 객체 생성을 못하게 막는다. 딱 하나의 객체만 생성되게.
//private은 가능 범위가 이 파일 내에서만 가능. 이 코드를 보고 싱글톤임을 알 수 있음.
private SingletonService() {
}
public void logic() {
System.out.println("싱글톤 객체 로직 호출");
}
}
->테스트해보면 두번 요청해도 같은 객체 반환. 하나 만들어두고 반환하는 형태.
+) isSameAs -객체 인스턴스 참조 비교(진짜 넣어서 비교). / equal은 실제 자바 .equals 메소드로 비교(모든 것을 비교하는 메소드)
->appConfig를 싱글톤으로 수정 필요 ?
스프링 컨테이너 사용하면 굳이 직접 수정 안해도 됨. 알아서 객체를 싱글톤으로 만들어서 관리해줌.
고객 요청 100개 와도 만들어놓은 1개의 객체 재활용(공유)함.
하지만 싱글톤 패턴은 수많은 문제가 있음.
- 싱글톤 패턴을 구현하는 코드 자체가 많음. (클래스 개수가 많아지기에)
- 의존 관계 상 클라이언트가 구체 클래스에 의존. getInstance로 객체 가져오는 것이기에 -> DIP위반, OCP 위반 가능성 높음.
- 테스트 하기가 어려움.인스터 미리 받아 설정이 먼저 끝나기에 유연하게 테스트하기 어려움.(유연성이 떨어짐)
- 내부 속성을 변경하거나 초기화 어렵다
- private 생성자->자식 생성하기 어려움.
- 결론적으로 유연성이 떨어져 DI 같은 것 적용 힘듬.
=>안티 패턴으로 불리기도.
=>>스프링이 싱글톤 패턴 문제, 단점 다 해결하고, 싱글톤이 적용된 싱글톤 컨테이너 제공.
그럼 어떻게 해결할까. 다음 게시물 확인해주세요!
'스프링 > 핵심원리-기본' 카테고리의 다른 글
복습 / 정리 (0) | 2022.11.23 |
---|---|
싱글톤 컨테이너 (0) | 2022.10.02 |
스프링 객체지향 설계 적용 (2) (0) | 2022.09.18 |
스프링에 객체지향 원리 적용 (0) | 2022.09.18 |
스프링 예제 (0) | 2022.09.06 |