[Spring] 싱글톤 패턴과 싱글톤 컨테이너

이지현·2023년 9월 13일
0

Spring

목록 보기
3/7
post-thumbnail
번호목차
1.싱글톤 패턴
2.싱글톤 컨테이너

1. 싱글톤 패턴

스프링 없는 순수한 DI 컨테이너

@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
    assertThat(memberService1).isNotSameAs(memberService2);
}

싱글톤 패턴을 적용한 객체 사용

@Test
@DisplayName("싱글톤 패턴을 적용한 객체 사용")
void singletonServiceTest() {
	// private로 생성자 막아둠, 컴파일 오류 발생
    // new SingletonService();

    // 1. 조회 : 호출할 때마다 같은 객체 반환
    SingletonService singletonService1 = SingletonService.getInstance();
    // 2. 조회 : 호출할 때마다 같은 객체 반환
    SingletonService singletonService2 = SingletonService.getInstance();

    // 참조값 같은 것 확인
    ystem.out.println("singletonService1 = " + singletonService1);
    System.out.println("singletonService2 = " + singletonService2);

    assertThat(singletonService1).isSameAs(singletonService2); // sameAs : ==, equal : equals
}
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() {}
}
  • 싱글톤 패턴 적용 시 고객의 요청이 올 때마다 객체를 생성하는 것이 아니라 이미 만들어진 객체를 공유해서 효율적으로 사용할 수 있음
  • 단점
    • 의존관계상 클라이언트가 구체 클래스에 의존함 -> DIP 위반
    • 클라이언트가 구체 클래스에 의존해 OCP 원칙을 위반할 가능성이 높음
    • 테스트가 어려워짐
    • 내부 속성을 변경하거나 초기화하기 어려움
    • private 생성자로 자식 클래스를 만들기 어려움
    • 결론적으로 유연성이 떨어지고 안티패턴으로 불리기도 함

2. 싱글톤 컨테이너

스프링 컨테이너와 싱글톤

@Test
@DisplayName("스프링 컨테이너와 싱글톤")
void springContainer() {
	// AppConfig appConfig = new AppConfig();
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(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);
}
  • 싱글톤 컨테이너 적용 후 고객의 요청이 올 때마다 객체를 생성하는 것이 아닌 이미 만들어진 객체를 공유해서 효율적으로 재사용할 수 있음
  • 싱글톤 컨테이너를 이용하면 싱글톤 패턴만 이용했을 때의 단점을 보완할 수 있음

🚫 주의점

  • 싱글톤 패턴과 스프링 같은 싱글톤 컨테이너처럼 객체 인스턴스를 하나만 생성해서 공유하는 싱글톤 방식은 여러 클라이언트가 하나의 같은 객체 인스턴스를 공유하기 때문에 상태유지(Stateful)하게 설계하면 안됨
  • 무상태(Stateless)로 설계해야 함
    • 특정 클라이언트에 의존적인 필드가 있으면 안됨
    • 특정 클라이언트가 값을 변경할 수 있는 필드가 있으면 안됨
    • 가급적 읽기만 가능해야 함
    • 필드 대신 자바에서 공유되지 않는 지역변수, 파라미터, ThreadLocal 등을 사용해야 함

@Configuration

  • 스프링 컨테이너는 싱글톤 레지스트리 -> 스프링 빈이 싱글톤이 되도록 보장해주어야 함
  • CGLIB 라이브러리는 @Bean이 붙은 메서드마다 이미 스프링 빈이 존재하면 존재하는 빈을 반환하고, 스프링 빈이 없으면 생성해서 스프링 빈으로 등록하고 반환하는 코드를 동적으로 만들어줌
    -> 싱글톤 보장
    -> Bean만 사용해도 스프링 빈으로 등록되지만, 싱글톤을 보장하지 않기 때문에 @Configuration을 사용해야 함

자료 출처

profile
2022.08 ~ 2023.09 / 현재 티스토리 이전 : https://jihyun-devstory.tistory.com/

0개의 댓글